CINXE.COM

cel-spec/doc/langdef.md at master · google/cel-spec · GitHub

<!DOCTYPE html> <html lang="en" data-color-mode="auto" data-light-theme="light" data-dark-theme="dark" data-a11y-animated-images="system" data-a11y-link-underlines="true" > <head> <meta charset="utf-8"> <link rel="dns-prefetch" href="https://github.githubassets.com"> <link rel="dns-prefetch" href="https://avatars.githubusercontent.com"> <link rel="dns-prefetch" href="https://github-cloud.s3.amazonaws.com"> <link rel="dns-prefetch" href="https://user-images.githubusercontent.com/"> <link rel="preconnect" href="https://github.githubassets.com" crossorigin> <link rel="preconnect" href="https://avatars.githubusercontent.com"> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/light-7aa84bb7e11e.css" /><link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/dark-f65db3e8d171.css" /><link data-color-theme="dark_dimmed" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_dimmed-a8258e3c6dda.css" /><link data-color-theme="dark_high_contrast" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_high_contrast-7e97d834719c.css" /><link data-color-theme="dark_colorblind" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_colorblind-01d869f460be.css" /><link data-color-theme="light_colorblind" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/light_colorblind-534f3e971240.css" /><link data-color-theme="light_high_contrast" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/light_high_contrast-a8cc7d138001.css" /><link data-color-theme="light_tritanopia" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/light_tritanopia-35e9dfdc4f9f.css" /><link data-color-theme="dark_tritanopia" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_tritanopia-cf4cc5f62dfe.css" /> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-primitives-d9abecd14f1e.css" /> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-93aded0ee8a1.css" /> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/global-8bed0685a4b5.css" /> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/github-a954a02d9269.css" /> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/repository-4fce88777fa8.css" /> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/code-0210be90f4d3.css" /> <script type="application/json" id="client-env">{"locale":"en","featureFlags":["bypass_copilot_indexing_quota","copilot_immersive_file_preview","copilot_new_references_ui","copilot_bing_skill_ga","copilot_attach_folder_reference","copilot_personal_instructions","copilot_personal_instructions_templates","copilot_chat_repo_custom_instructions_preview","copilot_chat_retry_on_error","copilot_chat_persist_submitted_input","copilot_conversational_ux_history_refs","copilot_chat_shared_chat_input","copilot_chat_shared_topic_indicator","copilot_chat_shared_repo_sso_banner","copilot_editor_upsells","copilot_dotcom_chat_reduce_telemetry","copilot_implicit_context","copilot_no_floating_button","copilot_smell_icebreaker_ux","copilot_read_shared_conversation","dotcom_chat_client_side_skills","copilot_new_markdown_renderer","experimentation_azure_variant_endpoint","failbot_handle_non_errors","geojson_azure_maps","ghost_pilot_confidence_truncation_25","ghost_pilot_confidence_truncation_40","github_models_o3_mini_streaming","hovercard_accessibility","issues_react_remove_placeholders","issues_react_blur_item_picker_on_close","issues_react_include_bots_in_pickers","marketing_pages_search_explore_provider","remove_child_patch","sample_network_conn_type","swp_enterprise_contact_form","site_copilot_vscode_link_update","site_proxima_australia_update","issues_react_create_milestone","issues_react_cache_fix_workaround","lifecycle_label_name_updates"]}</script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/wp-runtime-8f98335c0ff3.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_oddbird_popover-polyfill_dist_popover_js-9da652f58479.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_arianotify-polyfill_ariaNotify-polyfill_js-node_modules_github_mi-3abb8f-d7e6bc799724.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/ui_packages_failbot_failbot_ts-4600dbf2d60a.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/environment-f04cb2a9fc8c.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_primer_behaviors_dist_esm_index_mjs-0dbb79f97f8f.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_selector-observer_dist_index_esm_js-f690fd9ae3d5.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_relative-time-element_dist_index_js-f6da4b3fa34c.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_auto-complete-element_dist_index_js-node_modules_github_catalyst_-8e9f78-a74b4e0a8a6b.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_text-expander-element_dist_index_js-78748950cb0c.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_filter-input-element_dist_index_js-node_modules_github_remote-inp-b5f1d7-a1760ffda83d.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_markdown-toolbar-element_dist_index_js-ceef33f593fa.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_file-attachment-element_dist_index_js-node_modules_primer_view-co-c44a69-f0c8a795d1fd.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/github-elements-44d18ad044b3.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/element-registry-b7096f9a808d.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_braintree_browser-detection_dist_browser-detection_js-node_modules_githu-2906d7-2a07a295af40.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_lit-html_lit-html_js-be8cb88f481b.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_mini-throttle_dist_index_js-node_modules_morphdom_dist_morphdom-e-7c534c-a4a1922eb55f.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_turbo_dist_turbo_es2017-esm_js-e3cbe28f1638.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_remote-form_dist_index_js-node_modules_delegated-events_dist_inde-893f9f-6cf3320416b8.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_color-convert_index_js-e3180fe3bcb3.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_quote-selection_dist_index_js-node_modules_github_session-resume_-947061-205cd97df772.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/ui_packages_updatable-content_updatable-content_ts-a1563f62660e.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/app_assets_modules_github_behaviors_task-list_ts-app_assets_modules_github_sso_ts-ui_packages-900dde-f48a418a99d4.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/app_assets_modules_github_sticky-scroll-into-view_ts-8fa27fd7fbb6.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/app_assets_modules_github_behaviors_ajax-error_ts-app_assets_modules_github_behaviors_include-87a4ae-e2caa5390f5a.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/app_assets_modules_github_behaviors_commenting_edit_ts-app_assets_modules_github_behaviors_ht-83c235-783fc7e142e5.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/behaviors-854fa1987fb5.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_delegated-events_dist_index_js-node_modules_github_catalyst_lib_index_js-f6223d90c7ba.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/notifications-global-e12489347ccf.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_mini-throttle_dist_index_js-node_modules_github_catalyst_lib_inde-dbbea9-26cce2010167.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/code-menu-6a5f60eab447.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/primer-react-8e38c0ecf8b7.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/react-core-218ef2d63cca.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/react-lib-f1bca44e0926.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/octicons-react-611691cca2f6.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_emotion_is-prop-valid_dist_emotion-is-prop-valid_esm_js-node_modules_emo-62da9f-2df2f32ec596.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_mini-throttle_dist_index_js-node_modules_stacktrace-parser_dist_s-e7dcdd-f7cc96ebae76.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_oddbird_popover-polyfill_dist_popover-fn_js-55fea94174bf.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_dompurify_dist_purify_js-b89b98661809.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_lodash-es__Stack_js-node_modules_lodash-es__Uint8Array_js-node_modules_l-4faaa6-4a736fde5c2f.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_lodash-es__baseIsEqual_js-8929eb9718d5.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_hydro-analytics-client_dist_analytics-client_js-node_modules_gith-853b24-f2006d2a5b98.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_focus-visible_dist_focus-visible_js-node_modules_fzy_js_index_js-node_mo-35e85b-b2842e98946f.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/ui_packages_aria-live_aria-live_ts-ui_packages_promise-with-resolvers-polyfill_promise-with-r-17c672-d6b5ea82572a.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/ui_packages_paths_index_ts-73c512ff3577.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/ui_packages_ref-selector_RefSelector_tsx-2cce17df147b.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/ui_packages_code-view-shared_utilities_web-worker_ts-ui_packages_code-view-shared_worker-jobs-a69584-34e5b559ff45.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/ui_packages_code-view-shared_hooks_use-canonical-object_ts-ui_packages_code-view-shared_hooks-a6859a-09c7f754ea79.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/ui_packages_repos-file-tree-view_repos-file-tree-view_ts-ui_packages_feature-request_FeatureR-648c3b-e2701dc83e0b.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/app_assets_modules_github_blob-anchor_ts-ui_packages_code-nav_code-nav_ts-ui_packages_filter--8253c1-91468a3354f9.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/react-code-view-684bc66bc078.js"></script> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-react.f5cae0c610a2c4c470c2.module.css" /> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/react-code-view.ab7d8fac328c00e5e0cc.module.css" /> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/notifications-subscriptions-menu-eff84ecbf2b6.js"></script> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-react.f5cae0c610a2c4c470c2.module.css" /> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/notifications-subscriptions-menu.1bcff9205c241e99cff2.module.css" /> <title>cel-spec/doc/langdef.md at master · google/cel-spec · GitHub</title> <meta name="route-pattern" content="/:user_id/:repository/blob/*name(/*path)" data-turbo-transient> <meta name="route-controller" content="blob" data-turbo-transient> <meta name="route-action" content="show" data-turbo-transient> <meta name="current-catalog-service-hash" content="f3abb0cc802f3d7b95fc8762b94bdcb13bf39634c40c357301c4aa1d67a256fb"> <meta name="request-id" content="9C2E:E2206:BDF3A:DC0F5:67B31B24" data-pjax-transient="true"/><meta name="html-safe-nonce" content="f11591c77ceb5ac6744a099234042e16ccb43b67799acef2f33b60575fd8066d" data-pjax-transient="true"/><meta name="visitor-payload" content="eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiI5QzJFOkUyMjA2OkJERjNBOkRDMEY1OjY3QjMxQjI0IiwidmlzaXRvcl9pZCI6IjYyOTEwNDg1NjgyNTcxOTA2OTIiLCJyZWdpb25fZWRnZSI6InNvdXRoZWFzdGFzaWEiLCJyZWdpb25fcmVuZGVyIjoic291dGhlYXN0YXNpYSJ9" data-pjax-transient="true"/><meta name="visitor-hmac" content="f7d6d4b32657e6b404abefac2cee0d767ba93adc2664b18cc0fd061516c337ed" data-pjax-transient="true"/> <meta name="hovercard-subject-tag" content="repository:102390943" data-turbo-transient> <meta name="github-keyboard-shortcuts" content="repository,source-code,file-tree,copilot" data-turbo-transient="true" /> <meta name="selected-link" value="repo_source" data-turbo-transient> <link rel="assets" href="https://github.githubassets.com/"> <meta name="google-site-verification" content="Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I"> <meta name="octolytics-url" content="https://collector.github.com/github/collect" /> <meta name="analytics-location" content="/&lt;user-name&gt;/&lt;repo-name&gt;/blob/show" data-turbo-transient="true" /> <meta name="user-login" content=""> <meta name="viewport" content="width=device-width"> <meta name="description" content="Common Expression Language -- specification and binary representation - cel-spec/doc/langdef.md at master · google/cel-spec"> <link rel="search" type="application/opensearchdescription+xml" href="/opensearch.xml" title="GitHub"> <link rel="fluid-icon" href="https://github.com/fluidicon.png" title="GitHub"> <meta property="fb:app_id" content="1401488693436528"> <meta name="apple-itunes-app" content="app-id=1477376905, app-argument=https://github.com/google/cel-spec/blob/master/doc/langdef.md" /> <meta name="twitter:image" content="https://repository-images.githubusercontent.com/102390943/fb75fad4-436b-4c13-a3ca-b3ee548911b4" /><meta name="twitter:site" content="@github" /><meta name="twitter:card" content="summary_large_image" /><meta name="twitter:title" content="cel-spec/doc/langdef.md at master · google/cel-spec" /><meta name="twitter:description" content="Common Expression Language -- specification and binary representation - google/cel-spec" /> <meta property="og:image" content="https://repository-images.githubusercontent.com/102390943/fb75fad4-436b-4c13-a3ca-b3ee548911b4" /><meta property="og:image:alt" content="Common Expression Language -- specification and binary representation - google/cel-spec" /><meta property="og:site_name" content="GitHub" /><meta property="og:type" content="object" /><meta property="og:title" content="cel-spec/doc/langdef.md at master · google/cel-spec" /><meta property="og:url" content="https://github.com/google/cel-spec/blob/master/doc/langdef.md" /><meta property="og:description" content="Common Expression Language -- specification and binary representation - google/cel-spec" /> <meta name="hostname" content="github.com"> <meta name="expected-hostname" content="github.com"> <meta http-equiv="x-pjax-version" content="7285c1d48b26dbf4a947aa96973b0576ccc264b2eed60ad331fecccb5cc407f9" data-turbo-track="reload"> <meta http-equiv="x-pjax-csp-version" content="ace39c3b6632770952207593607e6e0be0db363435a8b877b1f96abe6430f345" data-turbo-track="reload"> <meta http-equiv="x-pjax-css-version" content="1c71206221e00a0a8e77d94d48d954f34ddbd711c4a0ced954fd49cd786cfa61" data-turbo-track="reload"> <meta http-equiv="x-pjax-js-version" content="e957203196628458a3ddb1546cfef8b3b07cafa937f5a0542f0fb75f6273f835" data-turbo-track="reload"> <meta name="turbo-cache-control" content="no-preview" data-turbo-transient=""> <meta name="turbo-cache-control" content="no-cache" data-turbo-transient> <meta data-hydrostats="publish"> <meta name="go-import" content="github.com/google/cel-spec git https://github.com/google/cel-spec.git"> <meta name="octolytics-dimension-user_id" content="1342004" /><meta name="octolytics-dimension-user_login" content="google" /><meta name="octolytics-dimension-repository_id" content="102390943" /><meta name="octolytics-dimension-repository_nwo" content="google/cel-spec" /><meta name="octolytics-dimension-repository_public" content="true" /><meta name="octolytics-dimension-repository_is_fork" content="false" /><meta name="octolytics-dimension-repository_network_root_id" content="102390943" /><meta name="octolytics-dimension-repository_network_root_nwo" content="google/cel-spec" /> <meta name="turbo-body-classes" content="logged-out env-production page-responsive"> <meta name="browser-stats-url" content="https://api.github.com/_private/browser/stats"> <meta name="browser-errors-url" content="https://api.github.com/_private/browser/errors"> <link rel="mask-icon" href="https://github.githubassets.com/assets/pinned-octocat-093da3e6fa40.svg" color="#000000"> <link rel="alternate icon" class="js-site-favicon" type="image/png" href="https://github.githubassets.com/favicons/favicon.png"> <link rel="icon" class="js-site-favicon" type="image/svg+xml" href="https://github.githubassets.com/favicons/favicon.svg" data-base-href="https://github.githubassets.com/favicons/favicon"> <meta name="theme-color" content="#1e2327"> <meta name="color-scheme" content="light dark" /> <link rel="manifest" href="/manifest.json" crossOrigin="use-credentials"> </head> <body class="logged-out env-production page-responsive" style="word-wrap: break-word;"> <div data-turbo-body class="logged-out env-production page-responsive" style="word-wrap: break-word;"> <div class="position-relative header-wrapper js-header-wrapper "> <a href="#start-of-content" data-skip-target-assigned="false" class="px-2 py-4 color-bg-accent-emphasis color-fg-on-emphasis show-on-focus js-skip-to-content">Skip to content</a> <span data-view-component="true" class="progress-pjax-loader Progress position-fixed width-full"> <span style="width: 0%;" data-view-component="true" class="Progress-item progress-pjax-loader-bar left-0 top-0 color-bg-accent-emphasis"></span> </span> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/ui_packages_ui-commands_ui-commands_ts-e571874765ef.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/keyboard-shortcuts-dialog-765cf28766da.js"></script> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-react.f5cae0c610a2c4c470c2.module.css" /> <react-partial partial-name="keyboard-shortcuts-dialog" data-ssr="false" data-attempted-ssr="false" > <script type="application/json" data-target="react-partial.embeddedData">{"props":{"docsUrl":"https://docs.github.com/get-started/accessibility/keyboard-shortcuts"}}</script> <div data-target="react-partial.reactRoot"></div> </react-partial> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_remote-form_dist_index_js-node_modules_delegated-events_dist_inde-94fd67-73b675cf164a.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/sessions-2d195d11c56b.js"></script> <header class="HeaderMktg header-logged-out js-details-container js-header Details f4 py-3" role="banner" data-is-top="true" data-color-mode=light data-light-theme=light data-dark-theme=dark> <h2 class="sr-only">Navigation Menu</h2> <button type="button" class="HeaderMktg-backdrop d-lg-none border-0 position-fixed top-0 left-0 width-full height-full js-details-target" aria-label="Toggle navigation"> <span class="d-none">Toggle navigation</span> </button> <div class="d-flex flex-column flex-lg-row flex-items-center px-3 px-md-4 px-lg-5 height-full position-relative z-1"> <div class="d-flex flex-justify-between flex-items-center width-full width-lg-auto"> <div class="flex-1"> <button aria-label="Toggle navigation" aria-expanded="false" type="button" data-view-component="true" class="js-details-target js-nav-padding-recalculate js-header-menu-toggle Button--link Button--medium Button d-lg-none color-fg-inherit p-1"> <span class="Button-content"> <span class="Button-label"><div class="HeaderMenu-toggle-bar rounded my-1"></div> <div class="HeaderMenu-toggle-bar rounded my-1"></div> <div class="HeaderMenu-toggle-bar rounded my-1"></div></span> </span> </button> </div> <a class="mr-lg-3 color-fg-inherit flex-order-2 js-prevent-focus-on-mobile-nav" href="/" aria-label="Homepage" data-analytics-event="{&quot;category&quot;:&quot;Marketing nav&quot;,&quot;action&quot;:&quot;click to go to homepage&quot;,&quot;label&quot;:&quot;ref_page:Marketing;ref_cta:Logomark;ref_loc:Header&quot;}"> <svg height="32" aria-hidden="true" viewBox="0 0 24 24" version="1.1" width="32" data-view-component="true" class="octicon octicon-mark-github"> <path d="M12.5.75C6.146.75 1 5.896 1 12.25c0 5.089 3.292 9.387 7.863 10.91.575.101.79-.244.79-.546 0-.273-.014-1.178-.014-2.142-2.889.532-3.636-.704-3.866-1.35-.13-.331-.69-1.352-1.18-1.625-.402-.216-.977-.748-.014-.762.906-.014 1.553.834 1.769 1.179 1.035 1.74 2.688 1.25 3.349.948.1-.747.402-1.25.733-1.538-2.559-.287-5.232-1.279-5.232-5.678 0-1.25.445-2.285 1.178-3.09-.115-.288-.517-1.467.115-3.048 0 0 .963-.302 3.163 1.179.92-.259 1.897-.388 2.875-.388.977 0 1.955.13 2.875.388 2.2-1.495 3.162-1.179 3.162-1.179.633 1.581.23 2.76.115 3.048.733.805 1.179 1.825 1.179 3.09 0 4.413-2.688 5.39-5.247 5.678.417.36.776 1.05.776 2.128 0 1.538-.014 2.774-.014 3.162 0 .302.216.662.79.547C20.709 21.637 24 17.324 24 12.25 24 5.896 18.854.75 12.5.75Z"></path> </svg> </a> <div class="flex-1 flex-order-2 text-right"> <a href="/login?return_to=https%3A%2F%2Fgithub.com%2Fgoogle%2Fcel-spec%2Fblob%2Fmaster%2Fdoc%2Flangdef.md" class="HeaderMenu-link HeaderMenu-button d-inline-flex d-lg-none flex-order-1 f5 no-underline border color-border-default rounded-2 px-2 py-1 color-fg-inherit js-prevent-focus-on-mobile-nav" data-hydro-click="{&quot;event_type&quot;:&quot;authentication.click&quot;,&quot;payload&quot;:{&quot;location_in_page&quot;:&quot;site header menu&quot;,&quot;repository_id&quot;:null,&quot;auth_type&quot;:&quot;SIGN_UP&quot;,&quot;originating_url&quot;:&quot;https://github.com/google/cel-spec/blob/master/doc/langdef.md&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="13775a14edcea7e1ce2688c156695c06fe9bd645faab95e63cdcbb83e1711c33" data-analytics-event="{&quot;category&quot;:&quot;Marketing nav&quot;,&quot;action&quot;:&quot;click to Sign in&quot;,&quot;label&quot;:&quot;ref_page:Marketing;ref_cta:Sign in;ref_loc:Header&quot;}" > Sign in </a> </div> </div> <div class="HeaderMenu js-header-menu height-fit position-lg-relative d-lg-flex flex-column flex-auto top-0"> <div class="HeaderMenu-wrapper d-flex flex-column flex-self-start flex-lg-row flex-auto rounded rounded-lg-0"> <nav class="HeaderMenu-nav" aria-label="Global"> <ul class="d-lg-flex list-style-none"> <li class="HeaderMenu-item position-relative flex-wrap flex-justify-between flex-items-center d-block d-lg-flex flex-lg-nowrap flex-lg-items-center js-details-container js-header-menu-item"> <button type="button" class="HeaderMenu-link border-0 width-full width-lg-auto px-0 px-lg-2 py-lg-2 no-wrap d-flex flex-items-center flex-justify-between js-details-target" aria-expanded="false"> Product <svg opacity="0.5" aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-chevron-down HeaderMenu-icon ml-1"> <path d="M12.78 5.22a.749.749 0 0 1 0 1.06l-4.25 4.25a.749.749 0 0 1-1.06 0L3.22 6.28a.749.749 0 1 1 1.06-1.06L8 8.939l3.72-3.719a.749.749 0 0 1 1.06 0Z"></path> </svg> </button> <div class="HeaderMenu-dropdown dropdown-menu rounded m-0 p-0 pt-2 pt-lg-4 position-relative position-lg-absolute left-0 left-lg-n3 pb-2 pb-lg-4 d-lg-flex flex-wrap dropdown-menu-wide"> <div class="HeaderMenu-column px-lg-4 border-lg-right mb-4 mb-lg-0 pr-lg-7"> <div class="border-bottom pb-3 pb-lg-0 border-lg-bottom-0"> <ul class="list-style-none f5" > <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description pb-lg-3" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;github_copilot&quot;,&quot;context&quot;:&quot;product&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;github_copilot_link_product_navbar&quot;}" href="https://github.com/features/copilot"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-copilot color-fg-subtle mr-3"> <path d="M23.922 16.992c-.861 1.495-5.859 5.023-11.922 5.023-6.063 0-11.061-3.528-11.922-5.023A.641.641 0 0 1 0 16.736v-2.869a.841.841 0 0 1 .053-.22c.372-.935 1.347-2.292 2.605-2.656.167-.429.414-1.055.644-1.517a10.195 10.195 0 0 1-.052-1.086c0-1.331.282-2.499 1.132-3.368.397-.406.89-.717 1.474-.952 1.399-1.136 3.392-2.093 6.122-2.093 2.731 0 4.767.957 6.166 2.093.584.235 1.077.546 1.474.952.85.869 1.132 2.037 1.132 3.368 0 .368-.014.733-.052 1.086.23.462.477 1.088.644 1.517 1.258.364 2.233 1.721 2.605 2.656a.832.832 0 0 1 .053.22v2.869a.641.641 0 0 1-.078.256ZM12.172 11h-.344a4.323 4.323 0 0 1-.355.508C10.703 12.455 9.555 13 7.965 13c-1.725 0-2.989-.359-3.782-1.259a2.005 2.005 0 0 1-.085-.104L4 11.741v6.585c1.435.779 4.514 2.179 8 2.179 3.486 0 6.565-1.4 8-2.179v-6.585l-.098-.104s-.033.045-.085.104c-.793.9-2.057 1.259-3.782 1.259-1.59 0-2.738-.545-3.508-1.492a4.323 4.323 0 0 1-.355-.508h-.016.016Zm.641-2.935c.136 1.057.403 1.913.878 2.497.442.544 1.134.938 2.344.938 1.573 0 2.292-.337 2.657-.751.384-.435.558-1.15.558-2.361 0-1.14-.243-1.847-.705-2.319-.477-.488-1.319-.862-2.824-1.025-1.487-.161-2.192.138-2.533.529-.269.307-.437.808-.438 1.578v.021c0 .265.021.562.063.893Zm-1.626 0c.042-.331.063-.628.063-.894v-.02c-.001-.77-.169-1.271-.438-1.578-.341-.391-1.046-.69-2.533-.529-1.505.163-2.347.537-2.824 1.025-.462.472-.705 1.179-.705 2.319 0 1.211.175 1.926.558 2.361.365.414 1.084.751 2.657.751 1.21 0 1.902-.394 2.344-.938.475-.584.742-1.44.878-2.497Z"></path><path d="M14.5 14.25a1 1 0 0 1 1 1v2a1 1 0 0 1-2 0v-2a1 1 0 0 1 1-1Zm-5 0a1 1 0 0 1 1 1v2a1 1 0 0 1-2 0v-2a1 1 0 0 1 1-1Z"></path> </svg> <div> <div class="color-fg-default h4">GitHub Copilot</div> Write better code with AI </div> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description pb-lg-3" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;security&quot;,&quot;context&quot;:&quot;product&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;security_link_product_navbar&quot;}" href="https://github.com/features/security"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-shield-check color-fg-subtle mr-3"> <path d="M16.53 9.78a.75.75 0 0 0-1.06-1.06L11 13.19l-1.97-1.97a.75.75 0 0 0-1.06 1.06l2.5 2.5a.75.75 0 0 0 1.06 0l5-5Z"></path><path d="m12.54.637 8.25 2.675A1.75 1.75 0 0 1 22 4.976V10c0 6.19-3.771 10.704-9.401 12.83a1.704 1.704 0 0 1-1.198 0C5.77 20.705 2 16.19 2 10V4.976c0-.758.489-1.43 1.21-1.664L11.46.637a1.748 1.748 0 0 1 1.08 0Zm-.617 1.426-8.25 2.676a.249.249 0 0 0-.173.237V10c0 5.46 3.28 9.483 8.43 11.426a.199.199 0 0 0 .14 0C17.22 19.483 20.5 15.461 20.5 10V4.976a.25.25 0 0 0-.173-.237l-8.25-2.676a.253.253 0 0 0-.154 0Z"></path> </svg> <div> <div class="color-fg-default h4">Security</div> Find and fix vulnerabilities </div> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description pb-lg-3" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;actions&quot;,&quot;context&quot;:&quot;product&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;actions_link_product_navbar&quot;}" href="https://github.com/features/actions"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-workflow color-fg-subtle mr-3"> <path d="M1 3a2 2 0 0 1 2-2h6.5a2 2 0 0 1 2 2v6.5a2 2 0 0 1-2 2H7v4.063C7 16.355 7.644 17 8.438 17H12.5v-2.5a2 2 0 0 1 2-2H21a2 2 0 0 1 2 2V21a2 2 0 0 1-2 2h-6.5a2 2 0 0 1-2-2v-2.5H8.437A2.939 2.939 0 0 1 5.5 15.562V11.5H3a2 2 0 0 1-2-2Zm2-.5a.5.5 0 0 0-.5.5v6.5a.5.5 0 0 0 .5.5h6.5a.5.5 0 0 0 .5-.5V3a.5.5 0 0 0-.5-.5ZM14.5 14a.5.5 0 0 0-.5.5V21a.5.5 0 0 0 .5.5H21a.5.5 0 0 0 .5-.5v-6.5a.5.5 0 0 0-.5-.5Z"></path> </svg> <div> <div class="color-fg-default h4">Actions</div> Automate any workflow </div> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description pb-lg-3" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;codespaces&quot;,&quot;context&quot;:&quot;product&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;codespaces_link_product_navbar&quot;}" href="https://github.com/features/codespaces"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-codespaces color-fg-subtle mr-3"> <path d="M3.5 3.75C3.5 2.784 4.284 2 5.25 2h13.5c.966 0 1.75.784 1.75 1.75v7.5A1.75 1.75 0 0 1 18.75 13H5.25a1.75 1.75 0 0 1-1.75-1.75Zm-2 12c0-.966.784-1.75 1.75-1.75h17.5c.966 0 1.75.784 1.75 1.75v4a1.75 1.75 0 0 1-1.75 1.75H3.25a1.75 1.75 0 0 1-1.75-1.75ZM5.25 3.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h13.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Zm-2 12a.25.25 0 0 0-.25.25v4c0 .138.112.25.25.25h17.5a.25.25 0 0 0 .25-.25v-4a.25.25 0 0 0-.25-.25Z"></path><path d="M10 17.75a.75.75 0 0 1 .75-.75h6.5a.75.75 0 0 1 0 1.5h-6.5a.75.75 0 0 1-.75-.75Zm-4 0a.75.75 0 0 1 .75-.75h.5a.75.75 0 0 1 0 1.5h-.5a.75.75 0 0 1-.75-.75Z"></path> </svg> <div> <div class="color-fg-default h4">Codespaces</div> Instant dev environments </div> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description pb-lg-3" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;issues&quot;,&quot;context&quot;:&quot;product&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;issues_link_product_navbar&quot;}" href="https://github.com/features/issues"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-issue-opened color-fg-subtle mr-3"> <path d="M12 1c6.075 0 11 4.925 11 11s-4.925 11-11 11S1 18.075 1 12 5.925 1 12 1ZM2.5 12a9.5 9.5 0 0 0 9.5 9.5 9.5 9.5 0 0 0 9.5-9.5A9.5 9.5 0 0 0 12 2.5 9.5 9.5 0 0 0 2.5 12Zm9.5 2a2 2 0 1 1-.001-3.999A2 2 0 0 1 12 14Z"></path> </svg> <div> <div class="color-fg-default h4">Issues</div> Plan and track work </div> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description pb-lg-3" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;code_review&quot;,&quot;context&quot;:&quot;product&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;code_review_link_product_navbar&quot;}" href="https://github.com/features/code-review"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-code-review color-fg-subtle mr-3"> <path d="M10.3 6.74a.75.75 0 0 1-.04 1.06l-2.908 2.7 2.908 2.7a.75.75 0 1 1-1.02 1.1l-3.5-3.25a.75.75 0 0 1 0-1.1l3.5-3.25a.75.75 0 0 1 1.06.04Zm3.44 1.06a.75.75 0 1 1 1.02-1.1l3.5 3.25a.75.75 0 0 1 0 1.1l-3.5 3.25a.75.75 0 1 1-1.02-1.1l2.908-2.7-2.908-2.7Z"></path><path d="M1.5 4.25c0-.966.784-1.75 1.75-1.75h17.5c.966 0 1.75.784 1.75 1.75v12.5a1.75 1.75 0 0 1-1.75 1.75h-9.69l-3.573 3.573A1.458 1.458 0 0 1 5 21.043V18.5H3.25a1.75 1.75 0 0 1-1.75-1.75ZM3.25 4a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h2.5a.75.75 0 0 1 .75.75v3.19l3.72-3.72a.749.749 0 0 1 .53-.22h10a.25.25 0 0 0 .25-.25V4.25a.25.25 0 0 0-.25-.25Z"></path> </svg> <div> <div class="color-fg-default h4">Code Review</div> Manage code changes </div> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description pb-lg-3" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;discussions&quot;,&quot;context&quot;:&quot;product&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;discussions_link_product_navbar&quot;}" href="https://github.com/features/discussions"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-comment-discussion color-fg-subtle mr-3"> <path d="M1.75 1h12.5c.966 0 1.75.784 1.75 1.75v9.5A1.75 1.75 0 0 1 14.25 14H8.061l-2.574 2.573A1.458 1.458 0 0 1 3 15.543V14H1.75A1.75 1.75 0 0 1 0 12.25v-9.5C0 1.784.784 1 1.75 1ZM1.5 2.75v9.5c0 .138.112.25.25.25h2a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h6.5a.25.25 0 0 0 .25-.25v-9.5a.25.25 0 0 0-.25-.25H1.75a.25.25 0 0 0-.25.25Z"></path><path d="M22.5 8.75a.25.25 0 0 0-.25-.25h-3.5a.75.75 0 0 1 0-1.5h3.5c.966 0 1.75.784 1.75 1.75v9.5A1.75 1.75 0 0 1 22.25 20H21v1.543a1.457 1.457 0 0 1-2.487 1.03L15.939 20H10.75A1.75 1.75 0 0 1 9 18.25v-1.465a.75.75 0 0 1 1.5 0v1.465c0 .138.112.25.25.25h5.5a.75.75 0 0 1 .53.22l2.72 2.72v-2.19a.75.75 0 0 1 .75-.75h2a.25.25 0 0 0 .25-.25v-9.5Z"></path> </svg> <div> <div class="color-fg-default h4">Discussions</div> Collaborate outside of code </div> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;code_search&quot;,&quot;context&quot;:&quot;product&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;code_search_link_product_navbar&quot;}" href="https://github.com/features/code-search"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-code-square color-fg-subtle mr-3"> <path d="M10.3 8.24a.75.75 0 0 1-.04 1.06L7.352 12l2.908 2.7a.75.75 0 1 1-1.02 1.1l-3.5-3.25a.75.75 0 0 1 0-1.1l3.5-3.25a.75.75 0 0 1 1.06.04Zm3.44 1.06a.75.75 0 1 1 1.02-1.1l3.5 3.25a.75.75 0 0 1 0 1.1l-3.5 3.25a.75.75 0 1 1-1.02-1.1l2.908-2.7-2.908-2.7Z"></path><path d="M2 3.75C2 2.784 2.784 2 3.75 2h16.5c.966 0 1.75.784 1.75 1.75v16.5A1.75 1.75 0 0 1 20.25 22H3.75A1.75 1.75 0 0 1 2 20.25Zm1.75-.25a.25.25 0 0 0-.25.25v16.5c0 .138.112.25.25.25h16.5a.25.25 0 0 0 .25-.25V3.75a.25.25 0 0 0-.25-.25Z"></path> </svg> <div> <div class="color-fg-default h4">Code Search</div> Find more, search less </div> </a></li> </ul> </div> </div> <div class="HeaderMenu-column px-lg-4"> <div class="border-bottom pb-3 pb-lg-0 border-lg-bottom-0 border-bottom-0"> <span class="d-block h4 color-fg-default my-1" id="product-explore-heading">Explore</span> <ul class="list-style-none f5" aria-labelledby="product-explore-heading"> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;all_features&quot;,&quot;context&quot;:&quot;product&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;all_features_link_product_navbar&quot;}" href="https://github.com/features"> All features </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary Link--external" target="_blank" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;documentation&quot;,&quot;context&quot;:&quot;product&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;documentation_link_product_navbar&quot;}" href="https://docs.github.com"> Documentation <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-link-external HeaderMenu-external-icon color-fg-subtle"> <path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path> </svg> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary Link--external" target="_blank" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;github_skills&quot;,&quot;context&quot;:&quot;product&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;github_skills_link_product_navbar&quot;}" href="https://skills.github.com"> GitHub Skills <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-link-external HeaderMenu-external-icon color-fg-subtle"> <path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path> </svg> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary Link--external" target="_blank" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;blog&quot;,&quot;context&quot;:&quot;product&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;blog_link_product_navbar&quot;}" href="https://github.blog"> Blog <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-link-external HeaderMenu-external-icon color-fg-subtle"> <path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path> </svg> </a></li> </ul> </div> </div> </div> </li> <li class="HeaderMenu-item position-relative flex-wrap flex-justify-between flex-items-center d-block d-lg-flex flex-lg-nowrap flex-lg-items-center js-details-container js-header-menu-item"> <button type="button" class="HeaderMenu-link border-0 width-full width-lg-auto px-0 px-lg-2 py-lg-2 no-wrap d-flex flex-items-center flex-justify-between js-details-target" aria-expanded="false"> Solutions <svg opacity="0.5" aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-chevron-down HeaderMenu-icon ml-1"> <path d="M12.78 5.22a.749.749 0 0 1 0 1.06l-4.25 4.25a.749.749 0 0 1-1.06 0L3.22 6.28a.749.749 0 1 1 1.06-1.06L8 8.939l3.72-3.719a.749.749 0 0 1 1.06 0Z"></path> </svg> </button> <div class="HeaderMenu-dropdown dropdown-menu rounded m-0 p-0 pt-2 pt-lg-4 position-relative position-lg-absolute left-0 left-lg-n3 d-lg-flex flex-wrap dropdown-menu-wide"> <div class="HeaderMenu-column px-lg-4 border-lg-right mb-4 mb-lg-0 pr-lg-7"> <div class="border-bottom pb-3 pb-lg-0 border-lg-bottom-0 pb-lg-3 mb-3 mb-lg-0"> <span class="d-block h4 color-fg-default my-1" id="solutions-by-company-size-heading">By company size</span> <ul class="list-style-none f5" aria-labelledby="solutions-by-company-size-heading"> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;enterprises&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;enterprises_link_solutions_navbar&quot;}" href="https://github.com/enterprise"> Enterprises </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;small_and_medium_teams&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;small_and_medium_teams_link_solutions_navbar&quot;}" href="https://github.com/team"> Small and medium teams </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;startups&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;startups_link_solutions_navbar&quot;}" href="https://github.com/enterprise/startups"> Startups </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;nonprofits&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;nonprofits_link_solutions_navbar&quot;}" href="/solutions/industry/nonprofits"> Nonprofits </a></li> </ul> </div> <div class="border-bottom pb-3 pb-lg-0 border-lg-bottom-0"> <span class="d-block h4 color-fg-default my-1" id="solutions-by-use-case-heading">By use case</span> <ul class="list-style-none f5" aria-labelledby="solutions-by-use-case-heading"> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;devsecops&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;devsecops_link_solutions_navbar&quot;}" href="/solutions/use-case/devsecops"> DevSecOps </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;devops&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;devops_link_solutions_navbar&quot;}" href="/solutions/use-case/devops"> DevOps </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;ci_cd&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;ci_cd_link_solutions_navbar&quot;}" href="/solutions/use-case/ci-cd"> CI/CD </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;view_all_use_cases&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;view_all_use_cases_link_solutions_navbar&quot;}" href="/solutions/use-case"> View all use cases </a></li> </ul> </div> </div> <div class="HeaderMenu-column px-lg-4"> <div class="border-bottom pb-3 pb-lg-0 border-lg-bottom-0"> <span class="d-block h4 color-fg-default my-1" id="solutions-by-industry-heading">By industry</span> <ul class="list-style-none f5" aria-labelledby="solutions-by-industry-heading"> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;healthcare&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;healthcare_link_solutions_navbar&quot;}" href="/solutions/industry/healthcare"> Healthcare </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;financial_services&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;financial_services_link_solutions_navbar&quot;}" href="/solutions/industry/financial-services"> Financial services </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;manufacturing&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;manufacturing_link_solutions_navbar&quot;}" href="/solutions/industry/manufacturing"> Manufacturing </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;government&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;government_link_solutions_navbar&quot;}" href="/solutions/industry/government"> Government </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;view_all_industries&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;view_all_industries_link_solutions_navbar&quot;}" href="/solutions/industry"> View all industries </a></li> </ul> </div> </div> <div class="HeaderMenu-trailing-link rounded-bottom-2 flex-shrink-0 mt-lg-4 px-lg-4 py-4 py-lg-3 f5 text-semibold"> <a href="/solutions"> View all solutions <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-chevron-right HeaderMenu-trailing-link-icon"> <path d="M6.22 3.22a.75.75 0 0 1 1.06 0l4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L9.94 8 6.22 4.28a.75.75 0 0 1 0-1.06Z"></path> </svg> </a> </div> </div> </li> <li class="HeaderMenu-item position-relative flex-wrap flex-justify-between flex-items-center d-block d-lg-flex flex-lg-nowrap flex-lg-items-center js-details-container js-header-menu-item"> <button type="button" class="HeaderMenu-link border-0 width-full width-lg-auto px-0 px-lg-2 py-lg-2 no-wrap d-flex flex-items-center flex-justify-between js-details-target" aria-expanded="false"> Resources <svg opacity="0.5" aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-chevron-down HeaderMenu-icon ml-1"> <path d="M12.78 5.22a.749.749 0 0 1 0 1.06l-4.25 4.25a.749.749 0 0 1-1.06 0L3.22 6.28a.749.749 0 1 1 1.06-1.06L8 8.939l3.72-3.719a.749.749 0 0 1 1.06 0Z"></path> </svg> </button> <div class="HeaderMenu-dropdown dropdown-menu rounded m-0 p-0 pt-2 pt-lg-4 position-relative position-lg-absolute left-0 left-lg-n3 pb-2 pb-lg-4 d-lg-flex flex-wrap dropdown-menu-wide"> <div class="HeaderMenu-column px-lg-4 border-lg-right mb-4 mb-lg-0 pr-lg-7"> <div class="border-bottom pb-3 pb-lg-0 border-lg-bottom-0"> <span class="d-block h4 color-fg-default my-1" id="resources-topics-heading">Topics</span> <ul class="list-style-none f5" aria-labelledby="resources-topics-heading"> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;ai&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;ai_link_resources_navbar&quot;}" href="/resources/articles/ai"> AI </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;devops&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;devops_link_resources_navbar&quot;}" href="/resources/articles/devops"> DevOps </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;security&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;security_link_resources_navbar&quot;}" href="/resources/articles/security"> Security </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;software_development&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;software_development_link_resources_navbar&quot;}" href="/resources/articles/software-development"> Software Development </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;view_all&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;view_all_link_resources_navbar&quot;}" href="/resources/articles"> View all </a></li> </ul> </div> </div> <div class="HeaderMenu-column px-lg-4"> <div class="border-bottom pb-3 pb-lg-0 border-lg-bottom-0 border-bottom-0"> <span class="d-block h4 color-fg-default my-1" id="resources-explore-heading">Explore</span> <ul class="list-style-none f5" aria-labelledby="resources-explore-heading"> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary Link--external" target="_blank" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;learning_pathways&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;learning_pathways_link_resources_navbar&quot;}" href="https://resources.github.com/learn/pathways"> Learning Pathways <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-link-external HeaderMenu-external-icon color-fg-subtle"> <path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path> </svg> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary Link--external" target="_blank" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;white_papers_ebooks_webinars&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;white_papers_ebooks_webinars_link_resources_navbar&quot;}" href="https://resources.github.com"> White papers, Ebooks, Webinars <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-link-external HeaderMenu-external-icon color-fg-subtle"> <path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path> </svg> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;customer_stories&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;customer_stories_link_resources_navbar&quot;}" href="https://github.com/customer-stories"> Customer Stories </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary Link--external" target="_blank" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;partners&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;partners_link_resources_navbar&quot;}" href="https://partner.github.com"> Partners <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-link-external HeaderMenu-external-icon color-fg-subtle"> <path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path> </svg> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;executive_insights&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;executive_insights_link_resources_navbar&quot;}" href="https://github.com/solutions/executive-insights"> Executive Insights </a></li> </ul> </div> </div> </div> </li> <li class="HeaderMenu-item position-relative flex-wrap flex-justify-between flex-items-center d-block d-lg-flex flex-lg-nowrap flex-lg-items-center js-details-container js-header-menu-item"> <button type="button" class="HeaderMenu-link border-0 width-full width-lg-auto px-0 px-lg-2 py-lg-2 no-wrap d-flex flex-items-center flex-justify-between js-details-target" aria-expanded="false"> Open Source <svg opacity="0.5" aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-chevron-down HeaderMenu-icon ml-1"> <path d="M12.78 5.22a.749.749 0 0 1 0 1.06l-4.25 4.25a.749.749 0 0 1-1.06 0L3.22 6.28a.749.749 0 1 1 1.06-1.06L8 8.939l3.72-3.719a.749.749 0 0 1 1.06 0Z"></path> </svg> </button> <div class="HeaderMenu-dropdown dropdown-menu rounded m-0 p-0 pt-2 pt-lg-4 position-relative position-lg-absolute left-0 left-lg-n3 pb-2 pb-lg-4 px-lg-4"> <div class="HeaderMenu-column"> <div class="border-bottom pb-3 pb-lg-0 pb-lg-3 mb-3 mb-lg-0 mb-lg-3"> <ul class="list-style-none f5" > <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;github_sponsors&quot;,&quot;context&quot;:&quot;open_source&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;github_sponsors_link_open_source_navbar&quot;}" href="/sponsors"> <div> <div class="color-fg-default h4">GitHub Sponsors</div> Fund open source developers </div> </a></li> </ul> </div> <div class="border-bottom pb-3 pb-lg-0 pb-lg-3 mb-3 mb-lg-0 mb-lg-3"> <ul class="list-style-none f5" > <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;the_readme_project&quot;,&quot;context&quot;:&quot;open_source&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;the_readme_project_link_open_source_navbar&quot;}" href="https://github.com/readme"> <div> <div class="color-fg-default h4">The ReadME Project</div> GitHub community articles </div> </a></li> </ul> </div> <div class="border-bottom pb-3 pb-lg-0 border-bottom-0"> <span class="d-block h4 color-fg-default my-1" id="open-source-repositories-heading">Repositories</span> <ul class="list-style-none f5" aria-labelledby="open-source-repositories-heading"> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;topics&quot;,&quot;context&quot;:&quot;open_source&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;topics_link_open_source_navbar&quot;}" href="https://github.com/topics"> Topics </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;trending&quot;,&quot;context&quot;:&quot;open_source&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;trending_link_open_source_navbar&quot;}" href="https://github.com/trending"> Trending </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;collections&quot;,&quot;context&quot;:&quot;open_source&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;collections_link_open_source_navbar&quot;}" href="https://github.com/collections"> Collections </a></li> </ul> </div> </div> </div> </li> <li class="HeaderMenu-item position-relative flex-wrap flex-justify-between flex-items-center d-block d-lg-flex flex-lg-nowrap flex-lg-items-center js-details-container js-header-menu-item"> <button type="button" class="HeaderMenu-link border-0 width-full width-lg-auto px-0 px-lg-2 py-lg-2 no-wrap d-flex flex-items-center flex-justify-between js-details-target" aria-expanded="false"> Enterprise <svg opacity="0.5" aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-chevron-down HeaderMenu-icon ml-1"> <path d="M12.78 5.22a.749.749 0 0 1 0 1.06l-4.25 4.25a.749.749 0 0 1-1.06 0L3.22 6.28a.749.749 0 1 1 1.06-1.06L8 8.939l3.72-3.719a.749.749 0 0 1 1.06 0Z"></path> </svg> </button> <div class="HeaderMenu-dropdown dropdown-menu rounded m-0 p-0 pt-2 pt-lg-4 position-relative position-lg-absolute left-0 left-lg-n3 pb-2 pb-lg-4 px-lg-4"> <div class="HeaderMenu-column"> <div class="border-bottom pb-3 pb-lg-0 pb-lg-3 mb-3 mb-lg-0 mb-lg-3"> <ul class="list-style-none f5" > <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;enterprise_platform&quot;,&quot;context&quot;:&quot;enterprise&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;enterprise_platform_link_enterprise_navbar&quot;}" href="/enterprise"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-stack color-fg-subtle mr-3"> <path d="M11.063 1.456a1.749 1.749 0 0 1 1.874 0l8.383 5.316a1.751 1.751 0 0 1 0 2.956l-8.383 5.316a1.749 1.749 0 0 1-1.874 0L2.68 9.728a1.751 1.751 0 0 1 0-2.956Zm1.071 1.267a.25.25 0 0 0-.268 0L3.483 8.039a.25.25 0 0 0 0 .422l8.383 5.316a.25.25 0 0 0 .268 0l8.383-5.316a.25.25 0 0 0 0-.422Z"></path><path d="M1.867 12.324a.75.75 0 0 1 1.035-.232l8.964 5.685a.25.25 0 0 0 .268 0l8.964-5.685a.75.75 0 0 1 .804 1.267l-8.965 5.685a1.749 1.749 0 0 1-1.874 0l-8.965-5.685a.75.75 0 0 1-.231-1.035Z"></path><path d="M1.867 16.324a.75.75 0 0 1 1.035-.232l8.964 5.685a.25.25 0 0 0 .268 0l8.964-5.685a.75.75 0 0 1 .804 1.267l-8.965 5.685a1.749 1.749 0 0 1-1.874 0l-8.965-5.685a.75.75 0 0 1-.231-1.035Z"></path> </svg> <div> <div class="color-fg-default h4">Enterprise platform</div> AI-powered developer platform </div> </a></li> </ul> </div> <div class="border-bottom pb-3 pb-lg-0 border-bottom-0"> <span class="d-block h4 color-fg-default my-1" id="enterprise-available-add-ons-heading">Available add-ons</span> <ul class="list-style-none f5" aria-labelledby="enterprise-available-add-ons-heading"> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description pb-lg-3" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;advanced_security&quot;,&quot;context&quot;:&quot;enterprise&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;advanced_security_link_enterprise_navbar&quot;}" href="https://github.com/enterprise/advanced-security"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-shield-check color-fg-subtle mr-3"> <path d="M16.53 9.78a.75.75 0 0 0-1.06-1.06L11 13.19l-1.97-1.97a.75.75 0 0 0-1.06 1.06l2.5 2.5a.75.75 0 0 0 1.06 0l5-5Z"></path><path d="m12.54.637 8.25 2.675A1.75 1.75 0 0 1 22 4.976V10c0 6.19-3.771 10.704-9.401 12.83a1.704 1.704 0 0 1-1.198 0C5.77 20.705 2 16.19 2 10V4.976c0-.758.489-1.43 1.21-1.664L11.46.637a1.748 1.748 0 0 1 1.08 0Zm-.617 1.426-8.25 2.676a.249.249 0 0 0-.173.237V10c0 5.46 3.28 9.483 8.43 11.426a.199.199 0 0 0 .14 0C17.22 19.483 20.5 15.461 20.5 10V4.976a.25.25 0 0 0-.173-.237l-8.25-2.676a.253.253 0 0 0-.154 0Z"></path> </svg> <div> <div class="color-fg-default h4">Advanced Security</div> Enterprise-grade security features </div> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description pb-lg-3" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;github_copilot&quot;,&quot;context&quot;:&quot;enterprise&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;github_copilot_link_enterprise_navbar&quot;}" href="/features/copilot#enterprise"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-copilot color-fg-subtle mr-3"> <path d="M23.922 16.992c-.861 1.495-5.859 5.023-11.922 5.023-6.063 0-11.061-3.528-11.922-5.023A.641.641 0 0 1 0 16.736v-2.869a.841.841 0 0 1 .053-.22c.372-.935 1.347-2.292 2.605-2.656.167-.429.414-1.055.644-1.517a10.195 10.195 0 0 1-.052-1.086c0-1.331.282-2.499 1.132-3.368.397-.406.89-.717 1.474-.952 1.399-1.136 3.392-2.093 6.122-2.093 2.731 0 4.767.957 6.166 2.093.584.235 1.077.546 1.474.952.85.869 1.132 2.037 1.132 3.368 0 .368-.014.733-.052 1.086.23.462.477 1.088.644 1.517 1.258.364 2.233 1.721 2.605 2.656a.832.832 0 0 1 .053.22v2.869a.641.641 0 0 1-.078.256ZM12.172 11h-.344a4.323 4.323 0 0 1-.355.508C10.703 12.455 9.555 13 7.965 13c-1.725 0-2.989-.359-3.782-1.259a2.005 2.005 0 0 1-.085-.104L4 11.741v6.585c1.435.779 4.514 2.179 8 2.179 3.486 0 6.565-1.4 8-2.179v-6.585l-.098-.104s-.033.045-.085.104c-.793.9-2.057 1.259-3.782 1.259-1.59 0-2.738-.545-3.508-1.492a4.323 4.323 0 0 1-.355-.508h-.016.016Zm.641-2.935c.136 1.057.403 1.913.878 2.497.442.544 1.134.938 2.344.938 1.573 0 2.292-.337 2.657-.751.384-.435.558-1.15.558-2.361 0-1.14-.243-1.847-.705-2.319-.477-.488-1.319-.862-2.824-1.025-1.487-.161-2.192.138-2.533.529-.269.307-.437.808-.438 1.578v.021c0 .265.021.562.063.893Zm-1.626 0c.042-.331.063-.628.063-.894v-.02c-.001-.77-.169-1.271-.438-1.578-.341-.391-1.046-.69-2.533-.529-1.505.163-2.347.537-2.824 1.025-.462.472-.705 1.179-.705 2.319 0 1.211.175 1.926.558 2.361.365.414 1.084.751 2.657.751 1.21 0 1.902-.394 2.344-.938.475-.584.742-1.44.878-2.497Z"></path><path d="M14.5 14.25a1 1 0 0 1 1 1v2a1 1 0 0 1-2 0v-2a1 1 0 0 1 1-1Zm-5 0a1 1 0 0 1 1 1v2a1 1 0 0 1-2 0v-2a1 1 0 0 1 1-1Z"></path> </svg> <div> <div class="color-fg-default h4">GitHub Copilot</div> Enterprise-grade AI features </div> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;premium_support&quot;,&quot;context&quot;:&quot;enterprise&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;premium_support_link_enterprise_navbar&quot;}" href="/premium-support"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-comment-discussion color-fg-subtle mr-3"> <path d="M1.75 1h12.5c.966 0 1.75.784 1.75 1.75v9.5A1.75 1.75 0 0 1 14.25 14H8.061l-2.574 2.573A1.458 1.458 0 0 1 3 15.543V14H1.75A1.75 1.75 0 0 1 0 12.25v-9.5C0 1.784.784 1 1.75 1ZM1.5 2.75v9.5c0 .138.112.25.25.25h2a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h6.5a.25.25 0 0 0 .25-.25v-9.5a.25.25 0 0 0-.25-.25H1.75a.25.25 0 0 0-.25.25Z"></path><path d="M22.5 8.75a.25.25 0 0 0-.25-.25h-3.5a.75.75 0 0 1 0-1.5h3.5c.966 0 1.75.784 1.75 1.75v9.5A1.75 1.75 0 0 1 22.25 20H21v1.543a1.457 1.457 0 0 1-2.487 1.03L15.939 20H10.75A1.75 1.75 0 0 1 9 18.25v-1.465a.75.75 0 0 1 1.5 0v1.465c0 .138.112.25.25.25h5.5a.75.75 0 0 1 .53.22l2.72 2.72v-2.19a.75.75 0 0 1 .75-.75h2a.25.25 0 0 0 .25-.25v-9.5Z"></path> </svg> <div> <div class="color-fg-default h4">Premium Support</div> Enterprise-grade 24/7 support </div> </a></li> </ul> </div> </div> </div> </li> <li class="HeaderMenu-item position-relative flex-wrap flex-justify-between flex-items-center d-block d-lg-flex flex-lg-nowrap flex-lg-items-center js-details-container js-header-menu-item"> <a class="HeaderMenu-link no-underline px-0 px-lg-2 py-3 py-lg-2 d-block d-lg-inline-block" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;pricing&quot;,&quot;context&quot;:&quot;global&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;pricing_link_global_navbar&quot;}" href="https://github.com/pricing">Pricing</a> </li> </ul> </nav> <div class="d-flex flex-column flex-lg-row width-full flex-justify-end flex-lg-items-center text-center mt-3 mt-lg-0 text-lg-left ml-lg-3"> <qbsearch-input class="search-input" data-scope="repo:google/cel-spec" data-custom-scopes-path="/search/custom_scopes" data-delete-custom-scopes-csrf="QUuLL8eSgwEMq_fS32P97kBKhno6B5lP-Ig-QR0KZGZuZZ-VZaxKwUNfYDlVb1gggKpIDMpipw_XW5nzxz6CiQ" data-max-custom-scopes="10" data-header-redesign-enabled="false" data-initial-value="" data-blackbird-suggestions-path="/search/suggestions" data-jump-to-suggestions-path="/_graphql/GetSuggestedNavigationDestinations" data-current-repository="google/cel-spec" data-current-org="google" data-current-owner="" data-logged-in="false" data-copilot-chat-enabled="false" data-nl-search-enabled="false" data-retain-scroll-position="true"> <div class="search-input-container search-with-dialog position-relative d-flex flex-row flex-items-center mr-4 rounded" data-action="click:qbsearch-input#searchInputContainerClicked" > <button type="button" class="header-search-button placeholder input-button form-control d-flex flex-1 flex-self-stretch flex-items-center no-wrap width-full py-0 pl-2 pr-0 text-left border-0 box-shadow-none" data-target="qbsearch-input.inputButton" aria-label="Search or jump to…" aria-haspopup="dialog" placeholder="Search or jump to..." data-hotkey=s,/ autocapitalize="off" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;searchbar&quot;,&quot;context&quot;:&quot;global&quot;,&quot;tag&quot;:&quot;input&quot;,&quot;label&quot;:&quot;searchbar_input_global_navbar&quot;}" data-action="click:qbsearch-input#handleExpand" > <div class="mr-2 color-fg-muted"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-search"> <path d="M10.68 11.74a6 6 0 0 1-7.922-8.982 6 6 0 0 1 8.982 7.922l3.04 3.04a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215ZM11.5 7a4.499 4.499 0 1 0-8.997 0A4.499 4.499 0 0 0 11.5 7Z"></path> </svg> </div> <span class="flex-1" data-target="qbsearch-input.inputButtonText">Search or jump to...</span> <div class="d-flex" data-target="qbsearch-input.hotkeyIndicator"> <svg xmlns="http://www.w3.org/2000/svg" width="22" height="20" aria-hidden="true" class="mr-1"><path fill="none" stroke="#979A9C" opacity=".4" d="M3.5.5h12c1.7 0 3 1.3 3 3v13c0 1.7-1.3 3-3 3h-12c-1.7 0-3-1.3-3-3v-13c0-1.7 1.3-3 3-3z"></path><path fill="#979A9C" d="M11.8 6L8 15.1h-.9L10.8 6h1z"></path></svg> </div> </button> <input type="hidden" name="type" class="js-site-search-type-field"> <div class="Overlay--hidden " data-modal-dialog-overlay> <modal-dialog data-action="close:qbsearch-input#handleClose cancel:qbsearch-input#handleClose" data-target="qbsearch-input.searchSuggestionsDialog" role="dialog" id="search-suggestions-dialog" aria-modal="true" aria-labelledby="search-suggestions-dialog-header" data-view-component="true" class="Overlay Overlay--width-large Overlay--height-auto"> <h1 id="search-suggestions-dialog-header" class="sr-only">Search code, repositories, users, issues, pull requests...</h1> <div class="Overlay-body Overlay-body--paddingNone"> <div data-view-component="true"> <div class="search-suggestions position-fixed width-full color-shadow-large border color-fg-default color-bg-default overflow-hidden d-flex flex-column query-builder-container" style="border-radius: 12px;" data-target="qbsearch-input.queryBuilderContainer" hidden > <!-- '"` --><!-- </textarea></xmp> --></option></form><form id="query-builder-test-form" action="" accept-charset="UTF-8" method="get"> <query-builder data-target="qbsearch-input.queryBuilder" id="query-builder-query-builder-test" data-filter-key=":" data-view-component="true" class="QueryBuilder search-query-builder"> <div class="FormControl FormControl--fullWidth"> <label id="query-builder-test-label" for="query-builder-test" class="FormControl-label sr-only"> Search </label> <div class="QueryBuilder-StyledInput width-fit " data-target="query-builder.styledInput" > <span id="query-builder-test-leadingvisual-wrap" class="FormControl-input-leadingVisualWrap QueryBuilder-leadingVisualWrap"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-search FormControl-input-leadingVisual"> <path d="M10.68 11.74a6 6 0 0 1-7.922-8.982 6 6 0 0 1 8.982 7.922l3.04 3.04a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215ZM11.5 7a4.499 4.499 0 1 0-8.997 0A4.499 4.499 0 0 0 11.5 7Z"></path> </svg> </span> <div data-target="query-builder.styledInputContainer" class="QueryBuilder-StyledInputContainer"> <div aria-hidden="true" class="QueryBuilder-StyledInputContent" data-target="query-builder.styledInputContent" ></div> <div class="QueryBuilder-InputWrapper"> <div aria-hidden="true" class="QueryBuilder-Sizer" data-target="query-builder.sizer"></div> <input id="query-builder-test" name="query-builder-test" value="" autocomplete="off" type="text" role="combobox" spellcheck="false" aria-expanded="false" aria-describedby="validation-e79781c6-547d-4ef8-ac8f-c6b0ea925bbd" data-target="query-builder.input" data-action=" input:query-builder#inputChange blur:query-builder#inputBlur keydown:query-builder#inputKeydown focus:query-builder#inputFocus " data-view-component="true" class="FormControl-input QueryBuilder-Input FormControl-medium" /> </div> </div> <span class="sr-only" id="query-builder-test-clear">Clear</span> <button role="button" id="query-builder-test-clear-button" aria-labelledby="query-builder-test-clear query-builder-test-label" data-target="query-builder.clearButton" data-action=" click:query-builder#clear focus:query-builder#clearButtonFocus blur:query-builder#clearButtonBlur " variant="small" hidden="hidden" type="button" data-view-component="true" class="Button Button--iconOnly Button--invisible Button--medium mr-1 px-2 py-0 d-flex flex-items-center rounded-1 color-fg-muted"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-x-circle-fill Button-visual"> <path d="M2.343 13.657A8 8 0 1 1 13.658 2.343 8 8 0 0 1 2.343 13.657ZM6.03 4.97a.751.751 0 0 0-1.042.018.751.751 0 0 0-.018 1.042L6.94 8 4.97 9.97a.749.749 0 0 0 .326 1.275.749.749 0 0 0 .734-.215L8 9.06l1.97 1.97a.749.749 0 0 0 1.275-.326.749.749 0 0 0-.215-.734L9.06 8l1.97-1.97a.749.749 0 0 0-.326-1.275.749.749 0 0 0-.734.215L8 6.94Z"></path> </svg> </button> </div> <template id="search-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-search"> <path d="M10.68 11.74a6 6 0 0 1-7.922-8.982 6 6 0 0 1 8.982 7.922l3.04 3.04a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215ZM11.5 7a4.499 4.499 0 1 0-8.997 0A4.499 4.499 0 0 0 11.5 7Z"></path> </svg> </template> <template id="code-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-code"> <path d="m11.28 3.22 4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.749.749 0 0 1-1.275-.326.749.749 0 0 1 .215-.734L13.94 8l-3.72-3.72a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215Zm-6.56 0a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042L2.06 8l3.72 3.72a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L.47 8.53a.75.75 0 0 1 0-1.06Z"></path> </svg> </template> <template id="file-code-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-file-code"> <path d="M4 1.75C4 .784 4.784 0 5.75 0h5.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v8.586A1.75 1.75 0 0 1 14.25 15h-9a.75.75 0 0 1 0-1.5h9a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 10 4.25V1.5H5.75a.25.25 0 0 0-.25.25v2.5a.75.75 0 0 1-1.5 0Zm1.72 4.97a.75.75 0 0 1 1.06 0l2 2a.75.75 0 0 1 0 1.06l-2 2a.749.749 0 0 1-1.275-.326.749.749 0 0 1 .215-.734l1.47-1.47-1.47-1.47a.75.75 0 0 1 0-1.06ZM3.28 7.78 1.81 9.25l1.47 1.47a.751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018l-2-2a.75.75 0 0 1 0-1.06l2-2a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042Zm8.22-6.218V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path> </svg> </template> <template id="history-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-history"> <path d="m.427 1.927 1.215 1.215a8.002 8.002 0 1 1-1.6 5.685.75.75 0 1 1 1.493-.154 6.5 6.5 0 1 0 1.18-4.458l1.358 1.358A.25.25 0 0 1 3.896 6H.25A.25.25 0 0 1 0 5.75V2.104a.25.25 0 0 1 .427-.177ZM7.75 4a.75.75 0 0 1 .75.75v2.992l2.028.812a.75.75 0 0 1-.557 1.392l-2.5-1A.751.751 0 0 1 7 8.25v-3.5A.75.75 0 0 1 7.75 4Z"></path> </svg> </template> <template id="repo-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-repo"> <path d="M2 2.5A2.5 2.5 0 0 1 4.5 0h8.75a.75.75 0 0 1 .75.75v12.5a.75.75 0 0 1-.75.75h-2.5a.75.75 0 0 1 0-1.5h1.75v-2h-8a1 1 0 0 0-.714 1.7.75.75 0 1 1-1.072 1.05A2.495 2.495 0 0 1 2 11.5Zm10.5-1h-8a1 1 0 0 0-1 1v6.708A2.486 2.486 0 0 1 4.5 9h8ZM5 12.25a.25.25 0 0 1 .25-.25h3.5a.25.25 0 0 1 .25.25v3.25a.25.25 0 0 1-.4.2l-1.45-1.087a.249.249 0 0 0-.3 0L5.4 15.7a.25.25 0 0 1-.4-.2Z"></path> </svg> </template> <template id="bookmark-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-bookmark"> <path d="M3 2.75C3 1.784 3.784 1 4.75 1h6.5c.966 0 1.75.784 1.75 1.75v11.5a.75.75 0 0 1-1.227.579L8 11.722l-3.773 3.107A.751.751 0 0 1 3 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v9.91l3.023-2.489a.75.75 0 0 1 .954 0l3.023 2.49V2.75a.25.25 0 0 0-.25-.25Z"></path> </svg> </template> <template id="plus-circle-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-plus-circle"> <path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Zm7.25-3.25v2.5h2.5a.75.75 0 0 1 0 1.5h-2.5v2.5a.75.75 0 0 1-1.5 0v-2.5h-2.5a.75.75 0 0 1 0-1.5h2.5v-2.5a.75.75 0 0 1 1.5 0Z"></path> </svg> </template> <template id="circle-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-dot-fill"> <path d="M8 4a4 4 0 1 1 0 8 4 4 0 0 1 0-8Z"></path> </svg> </template> <template id="trash-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-trash"> <path d="M11 1.75V3h2.25a.75.75 0 0 1 0 1.5H2.75a.75.75 0 0 1 0-1.5H5V1.75C5 .784 5.784 0 6.75 0h2.5C10.216 0 11 .784 11 1.75ZM4.496 6.675l.66 6.6a.25.25 0 0 0 .249.225h5.19a.25.25 0 0 0 .249-.225l.66-6.6a.75.75 0 0 1 1.492.149l-.66 6.6A1.748 1.748 0 0 1 10.595 15h-5.19a1.75 1.75 0 0 1-1.741-1.575l-.66-6.6a.75.75 0 1 1 1.492-.15ZM6.5 1.75V3h3V1.75a.25.25 0 0 0-.25-.25h-2.5a.25.25 0 0 0-.25.25Z"></path> </svg> </template> <template id="team-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-people"> <path d="M2 5.5a3.5 3.5 0 1 1 5.898 2.549 5.508 5.508 0 0 1 3.034 4.084.75.75 0 1 1-1.482.235 4 4 0 0 0-7.9 0 .75.75 0 0 1-1.482-.236A5.507 5.507 0 0 1 3.102 8.05 3.493 3.493 0 0 1 2 5.5ZM11 4a3.001 3.001 0 0 1 2.22 5.018 5.01 5.01 0 0 1 2.56 3.012.749.749 0 0 1-.885.954.752.752 0 0 1-.549-.514 3.507 3.507 0 0 0-2.522-2.372.75.75 0 0 1-.574-.73v-.352a.75.75 0 0 1 .416-.672A1.5 1.5 0 0 0 11 5.5.75.75 0 0 1 11 4Zm-5.5-.5a2 2 0 1 0-.001 3.999A2 2 0 0 0 5.5 3.5Z"></path> </svg> </template> <template id="project-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-project"> <path d="M1.75 0h12.5C15.216 0 16 .784 16 1.75v12.5A1.75 1.75 0 0 1 14.25 16H1.75A1.75 1.75 0 0 1 0 14.25V1.75C0 .784.784 0 1.75 0ZM1.5 1.75v12.5c0 .138.112.25.25.25h12.5a.25.25 0 0 0 .25-.25V1.75a.25.25 0 0 0-.25-.25H1.75a.25.25 0 0 0-.25.25ZM11.75 3a.75.75 0 0 1 .75.75v7.5a.75.75 0 0 1-1.5 0v-7.5a.75.75 0 0 1 .75-.75Zm-8.25.75a.75.75 0 0 1 1.5 0v5.5a.75.75 0 0 1-1.5 0ZM8 3a.75.75 0 0 1 .75.75v3.5a.75.75 0 0 1-1.5 0v-3.5A.75.75 0 0 1 8 3Z"></path> </svg> </template> <template id="pencil-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-pencil"> <path d="M11.013 1.427a1.75 1.75 0 0 1 2.474 0l1.086 1.086a1.75 1.75 0 0 1 0 2.474l-8.61 8.61c-.21.21-.47.364-.756.445l-3.251.93a.75.75 0 0 1-.927-.928l.929-3.25c.081-.286.235-.547.445-.758l8.61-8.61Zm.176 4.823L9.75 4.81l-6.286 6.287a.253.253 0 0 0-.064.108l-.558 1.953 1.953-.558a.253.253 0 0 0 .108-.064Zm1.238-3.763a.25.25 0 0 0-.354 0L10.811 3.75l1.439 1.44 1.263-1.263a.25.25 0 0 0 0-.354Z"></path> </svg> </template> <template id="copilot-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-copilot"> <path d="M7.998 15.035c-4.562 0-7.873-2.914-7.998-3.749V9.338c.085-.628.677-1.686 1.588-2.065.013-.07.024-.143.036-.218.029-.183.06-.384.126-.612-.201-.508-.254-1.084-.254-1.656 0-.87.128-1.769.693-2.484.579-.733 1.494-1.124 2.724-1.261 1.206-.134 2.262.034 2.944.765.05.053.096.108.139.165.044-.057.094-.112.143-.165.682-.731 1.738-.899 2.944-.765 1.23.137 2.145.528 2.724 1.261.566.715.693 1.614.693 2.484 0 .572-.053 1.148-.254 1.656.066.228.098.429.126.612.012.076.024.148.037.218.924.385 1.522 1.471 1.591 2.095v1.872c0 .766-3.351 3.795-8.002 3.795Zm0-1.485c2.28 0 4.584-1.11 5.002-1.433V7.862l-.023-.116c-.49.21-1.075.291-1.727.291-1.146 0-2.059-.327-2.71-.991A3.222 3.222 0 0 1 8 6.303a3.24 3.24 0 0 1-.544.743c-.65.664-1.563.991-2.71.991-.652 0-1.236-.081-1.727-.291l-.023.116v4.255c.419.323 2.722 1.433 5.002 1.433ZM6.762 2.83c-.193-.206-.637-.413-1.682-.297-1.019.113-1.479.404-1.713.7-.247.312-.369.789-.369 1.554 0 .793.129 1.171.308 1.371.162.181.519.379 1.442.379.853 0 1.339-.235 1.638-.54.315-.322.527-.827.617-1.553.117-.935-.037-1.395-.241-1.614Zm4.155-.297c-1.044-.116-1.488.091-1.681.297-.204.219-.359.679-.242 1.614.091.726.303 1.231.618 1.553.299.305.784.54 1.638.54.922 0 1.28-.198 1.442-.379.179-.2.308-.578.308-1.371 0-.765-.123-1.242-.37-1.554-.233-.296-.693-.587-1.713-.7Z"></path><path d="M6.25 9.037a.75.75 0 0 1 .75.75v1.501a.75.75 0 0 1-1.5 0V9.787a.75.75 0 0 1 .75-.75Zm4.25.75v1.501a.75.75 0 0 1-1.5 0V9.787a.75.75 0 0 1 1.5 0Z"></path> </svg> </template> <template id="copilot-error-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-copilot-error"> <path d="M16 11.24c0 .112-.072.274-.21.467L13 9.688V7.862l-.023-.116c-.49.21-1.075.291-1.727.291-.198 0-.388-.009-.571-.029L6.833 5.226a4.01 4.01 0 0 0 .17-.782c.117-.935-.037-1.395-.241-1.614-.193-.206-.637-.413-1.682-.297-.683.076-1.115.231-1.395.415l-1.257-.91c.579-.564 1.413-.877 2.485-.996 1.206-.134 2.262.034 2.944.765.05.053.096.108.139.165.044-.057.094-.112.143-.165.682-.731 1.738-.899 2.944-.765 1.23.137 2.145.528 2.724 1.261.566.715.693 1.614.693 2.484 0 .572-.053 1.148-.254 1.656.066.228.098.429.126.612.012.076.024.148.037.218.924.385 1.522 1.471 1.591 2.095Zm-5.083-8.707c-1.044-.116-1.488.091-1.681.297-.204.219-.359.679-.242 1.614.091.726.303 1.231.618 1.553.299.305.784.54 1.638.54.922 0 1.28-.198 1.442-.379.179-.2.308-.578.308-1.371 0-.765-.123-1.242-.37-1.554-.233-.296-.693-.587-1.713-.7Zm2.511 11.074c-1.393.776-3.272 1.428-5.43 1.428-4.562 0-7.873-2.914-7.998-3.749V9.338c.085-.628.677-1.686 1.588-2.065.013-.07.024-.143.036-.218.029-.183.06-.384.126-.612-.18-.455-.241-.963-.252-1.475L.31 4.107A.747.747 0 0 1 0 3.509V3.49a.748.748 0 0 1 .625-.73c.156-.026.306.047.435.139l14.667 10.578a.592.592 0 0 1 .227.264.752.752 0 0 1 .046.249v.022a.75.75 0 0 1-1.19.596Zm-1.367-.991L5.635 7.964a5.128 5.128 0 0 1-.889.073c-.652 0-1.236-.081-1.727-.291l-.023.116v4.255c.419.323 2.722 1.433 5.002 1.433 1.539 0 3.089-.505 4.063-.934Z"></path> </svg> </template> <template id="workflow-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-workflow"> <path d="M0 1.75C0 .784.784 0 1.75 0h3.5C6.216 0 7 .784 7 1.75v3.5A1.75 1.75 0 0 1 5.25 7H4v4a1 1 0 0 0 1 1h4v-1.25C9 9.784 9.784 9 10.75 9h3.5c.966 0 1.75.784 1.75 1.75v3.5A1.75 1.75 0 0 1 14.25 16h-3.5A1.75 1.75 0 0 1 9 14.25v-.75H5A2.5 2.5 0 0 1 2.5 11V7h-.75A1.75 1.75 0 0 1 0 5.25Zm1.75-.25a.25.25 0 0 0-.25.25v3.5c0 .138.112.25.25.25h3.5a.25.25 0 0 0 .25-.25v-3.5a.25.25 0 0 0-.25-.25Zm9 9a.25.25 0 0 0-.25.25v3.5c0 .138.112.25.25.25h3.5a.25.25 0 0 0 .25-.25v-3.5a.25.25 0 0 0-.25-.25Z"></path> </svg> </template> <template id="book-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-book"> <path d="M0 1.75A.75.75 0 0 1 .75 1h4.253c1.227 0 2.317.59 3 1.501A3.743 3.743 0 0 1 11.006 1h4.245a.75.75 0 0 1 .75.75v10.5a.75.75 0 0 1-.75.75h-4.507a2.25 2.25 0 0 0-1.591.659l-.622.621a.75.75 0 0 1-1.06 0l-.622-.621A2.25 2.25 0 0 0 5.258 13H.75a.75.75 0 0 1-.75-.75Zm7.251 10.324.004-5.073-.002-2.253A2.25 2.25 0 0 0 5.003 2.5H1.5v9h3.757a3.75 3.75 0 0 1 1.994.574ZM8.755 4.75l-.004 7.322a3.752 3.752 0 0 1 1.992-.572H14.5v-9h-3.495a2.25 2.25 0 0 0-2.25 2.25Z"></path> </svg> </template> <template id="code-review-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-code-review"> <path d="M1.75 1h12.5c.966 0 1.75.784 1.75 1.75v8.5A1.75 1.75 0 0 1 14.25 13H8.061l-2.574 2.573A1.458 1.458 0 0 1 3 14.543V13H1.75A1.75 1.75 0 0 1 0 11.25v-8.5C0 1.784.784 1 1.75 1ZM1.5 2.75v8.5c0 .138.112.25.25.25h2a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h6.5a.25.25 0 0 0 .25-.25v-8.5a.25.25 0 0 0-.25-.25H1.75a.25.25 0 0 0-.25.25Zm5.28 1.72a.75.75 0 0 1 0 1.06L5.31 7l1.47 1.47a.751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018l-2-2a.75.75 0 0 1 0-1.06l2-2a.75.75 0 0 1 1.06 0Zm2.44 0a.75.75 0 0 1 1.06 0l2 2a.75.75 0 0 1 0 1.06l-2 2a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L10.69 7 9.22 5.53a.75.75 0 0 1 0-1.06Z"></path> </svg> </template> <template id="codespaces-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-codespaces"> <path d="M0 11.25c0-.966.784-1.75 1.75-1.75h12.5c.966 0 1.75.784 1.75 1.75v3A1.75 1.75 0 0 1 14.25 16H1.75A1.75 1.75 0 0 1 0 14.25Zm2-9.5C2 .784 2.784 0 3.75 0h8.5C13.216 0 14 .784 14 1.75v5a1.75 1.75 0 0 1-1.75 1.75h-8.5A1.75 1.75 0 0 1 2 6.75Zm1.75-.25a.25.25 0 0 0-.25.25v5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-5a.25.25 0 0 0-.25-.25Zm-2 9.5a.25.25 0 0 0-.25.25v3c0 .138.112.25.25.25h12.5a.25.25 0 0 0 .25-.25v-3a.25.25 0 0 0-.25-.25Z"></path><path d="M7 12.75a.75.75 0 0 1 .75-.75h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1-.75-.75Zm-4 0a.75.75 0 0 1 .75-.75h.5a.75.75 0 0 1 0 1.5h-.5a.75.75 0 0 1-.75-.75Z"></path> </svg> </template> <template id="comment-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-comment"> <path d="M1 2.75C1 1.784 1.784 1 2.75 1h10.5c.966 0 1.75.784 1.75 1.75v7.5A1.75 1.75 0 0 1 13.25 12H9.06l-2.573 2.573A1.458 1.458 0 0 1 4 13.543V12H2.75A1.75 1.75 0 0 1 1 10.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h2a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h4.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path> </svg> </template> <template id="comment-discussion-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-comment-discussion"> <path d="M1.75 1h8.5c.966 0 1.75.784 1.75 1.75v5.5A1.75 1.75 0 0 1 10.25 10H7.061l-2.574 2.573A1.458 1.458 0 0 1 2 11.543V10h-.25A1.75 1.75 0 0 1 0 8.25v-5.5C0 1.784.784 1 1.75 1ZM1.5 2.75v5.5c0 .138.112.25.25.25h1a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h3.5a.25.25 0 0 0 .25-.25v-5.5a.25.25 0 0 0-.25-.25h-8.5a.25.25 0 0 0-.25.25Zm13 2a.25.25 0 0 0-.25-.25h-.5a.75.75 0 0 1 0-1.5h.5c.966 0 1.75.784 1.75 1.75v5.5A1.75 1.75 0 0 1 14.25 12H14v1.543a1.458 1.458 0 0 1-2.487 1.03L9.22 12.28a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215l2.22 2.22v-2.19a.75.75 0 0 1 .75-.75h1a.25.25 0 0 0 .25-.25Z"></path> </svg> </template> <template id="organization-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-organization"> <path d="M1.75 16A1.75 1.75 0 0 1 0 14.25V1.75C0 .784.784 0 1.75 0h8.5C11.216 0 12 .784 12 1.75v12.5c0 .085-.006.168-.018.25h2.268a.25.25 0 0 0 .25-.25V8.285a.25.25 0 0 0-.111-.208l-1.055-.703a.749.749 0 1 1 .832-1.248l1.055.703c.487.325.779.871.779 1.456v5.965A1.75 1.75 0 0 1 14.25 16h-3.5a.766.766 0 0 1-.197-.026c-.099.017-.2.026-.303.026h-3a.75.75 0 0 1-.75-.75V14h-1v1.25a.75.75 0 0 1-.75.75Zm-.25-1.75c0 .138.112.25.25.25H4v-1.25a.75.75 0 0 1 .75-.75h2.5a.75.75 0 0 1 .75.75v1.25h2.25a.25.25 0 0 0 .25-.25V1.75a.25.25 0 0 0-.25-.25h-8.5a.25.25 0 0 0-.25.25ZM3.75 6h.5a.75.75 0 0 1 0 1.5h-.5a.75.75 0 0 1 0-1.5ZM3 3.75A.75.75 0 0 1 3.75 3h.5a.75.75 0 0 1 0 1.5h-.5A.75.75 0 0 1 3 3.75Zm4 3A.75.75 0 0 1 7.75 6h.5a.75.75 0 0 1 0 1.5h-.5A.75.75 0 0 1 7 6.75ZM7.75 3h.5a.75.75 0 0 1 0 1.5h-.5a.75.75 0 0 1 0-1.5ZM3 9.75A.75.75 0 0 1 3.75 9h.5a.75.75 0 0 1 0 1.5h-.5A.75.75 0 0 1 3 9.75ZM7.75 9h.5a.75.75 0 0 1 0 1.5h-.5a.75.75 0 0 1 0-1.5Z"></path> </svg> </template> <template id="rocket-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-rocket"> <path d="M14.064 0h.186C15.216 0 16 .784 16 1.75v.186a8.752 8.752 0 0 1-2.564 6.186l-.458.459c-.314.314-.641.616-.979.904v3.207c0 .608-.315 1.172-.833 1.49l-2.774 1.707a.749.749 0 0 1-1.11-.418l-.954-3.102a1.214 1.214 0 0 1-.145-.125L3.754 9.816a1.218 1.218 0 0 1-.124-.145L.528 8.717a.749.749 0 0 1-.418-1.11l1.71-2.774A1.748 1.748 0 0 1 3.31 4h3.204c.288-.338.59-.665.904-.979l.459-.458A8.749 8.749 0 0 1 14.064 0ZM8.938 3.623h-.002l-.458.458c-.76.76-1.437 1.598-2.02 2.5l-1.5 2.317 2.143 2.143 2.317-1.5c.902-.583 1.74-1.26 2.499-2.02l.459-.458a7.25 7.25 0 0 0 2.123-5.127V1.75a.25.25 0 0 0-.25-.25h-.186a7.249 7.249 0 0 0-5.125 2.123ZM3.56 14.56c-.732.732-2.334 1.045-3.005 1.148a.234.234 0 0 1-.201-.064.234.234 0 0 1-.064-.201c.103-.671.416-2.273 1.15-3.003a1.502 1.502 0 1 1 2.12 2.12Zm6.94-3.935c-.088.06-.177.118-.266.175l-2.35 1.521.548 1.783 1.949-1.2a.25.25 0 0 0 .119-.213ZM3.678 8.116 5.2 5.766c.058-.09.117-.178.176-.266H3.309a.25.25 0 0 0-.213.119l-1.2 1.95ZM12 5a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path> </svg> </template> <template id="shield-check-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-shield-check"> <path d="m8.533.133 5.25 1.68A1.75 1.75 0 0 1 15 3.48V7c0 1.566-.32 3.182-1.303 4.682-.983 1.498-2.585 2.813-5.032 3.855a1.697 1.697 0 0 1-1.33 0c-2.447-1.042-4.049-2.357-5.032-3.855C1.32 10.182 1 8.566 1 7V3.48a1.75 1.75 0 0 1 1.217-1.667l5.25-1.68a1.748 1.748 0 0 1 1.066 0Zm-.61 1.429.001.001-5.25 1.68a.251.251 0 0 0-.174.237V7c0 1.36.275 2.666 1.057 3.859.784 1.194 2.121 2.342 4.366 3.298a.196.196 0 0 0 .154 0c2.245-.957 3.582-2.103 4.366-3.297C13.225 9.666 13.5 8.358 13.5 7V3.48a.25.25 0 0 0-.174-.238l-5.25-1.68a.25.25 0 0 0-.153 0ZM11.28 6.28l-3.5 3.5a.75.75 0 0 1-1.06 0l-1.5-1.5a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215l.97.97 2.97-2.97a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042Z"></path> </svg> </template> <template id="heart-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-heart"> <path d="m8 14.25.345.666a.75.75 0 0 1-.69 0l-.008-.004-.018-.01a7.152 7.152 0 0 1-.31-.17 22.055 22.055 0 0 1-3.434-2.414C2.045 10.731 0 8.35 0 5.5 0 2.836 2.086 1 4.25 1 5.797 1 7.153 1.802 8 3.02 8.847 1.802 10.203 1 11.75 1 13.914 1 16 2.836 16 5.5c0 2.85-2.045 5.231-3.885 6.818a22.066 22.066 0 0 1-3.744 2.584l-.018.01-.006.003h-.002ZM4.25 2.5c-1.336 0-2.75 1.164-2.75 3 0 2.15 1.58 4.144 3.365 5.682A20.58 20.58 0 0 0 8 13.393a20.58 20.58 0 0 0 3.135-2.211C12.92 9.644 14.5 7.65 14.5 5.5c0-1.836-1.414-3-2.75-3-1.373 0-2.609.986-3.029 2.456a.749.749 0 0 1-1.442 0C6.859 3.486 5.623 2.5 4.25 2.5Z"></path> </svg> </template> <template id="server-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-server"> <path d="M1.75 1h12.5c.966 0 1.75.784 1.75 1.75v4c0 .372-.116.717-.314 1 .198.283.314.628.314 1v4a1.75 1.75 0 0 1-1.75 1.75H1.75A1.75 1.75 0 0 1 0 12.75v-4c0-.358.109-.707.314-1a1.739 1.739 0 0 1-.314-1v-4C0 1.784.784 1 1.75 1ZM1.5 2.75v4c0 .138.112.25.25.25h12.5a.25.25 0 0 0 .25-.25v-4a.25.25 0 0 0-.25-.25H1.75a.25.25 0 0 0-.25.25Zm.25 5.75a.25.25 0 0 0-.25.25v4c0 .138.112.25.25.25h12.5a.25.25 0 0 0 .25-.25v-4a.25.25 0 0 0-.25-.25ZM7 4.75A.75.75 0 0 1 7.75 4h4.5a.75.75 0 0 1 0 1.5h-4.5A.75.75 0 0 1 7 4.75ZM7.75 10h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1 0-1.5ZM3 4.75A.75.75 0 0 1 3.75 4h.5a.75.75 0 0 1 0 1.5h-.5A.75.75 0 0 1 3 4.75ZM3.75 10h.5a.75.75 0 0 1 0 1.5h-.5a.75.75 0 0 1 0-1.5Z"></path> </svg> </template> <template id="globe-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-globe"> <path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM5.78 8.75a9.64 9.64 0 0 0 1.363 4.177c.255.426.542.832.857 1.215.245-.296.551-.705.857-1.215A9.64 9.64 0 0 0 10.22 8.75Zm4.44-1.5a9.64 9.64 0 0 0-1.363-4.177c-.307-.51-.612-.919-.857-1.215a9.927 9.927 0 0 0-.857 1.215A9.64 9.64 0 0 0 5.78 7.25Zm-5.944 1.5H1.543a6.507 6.507 0 0 0 4.666 5.5c-.123-.181-.24-.365-.352-.552-.715-1.192-1.437-2.874-1.581-4.948Zm-2.733-1.5h2.733c.144-2.074.866-3.756 1.58-4.948.12-.197.237-.381.353-.552a6.507 6.507 0 0 0-4.666 5.5Zm10.181 1.5c-.144 2.074-.866 3.756-1.58 4.948-.12.197-.237.381-.353.552a6.507 6.507 0 0 0 4.666-5.5Zm2.733-1.5a6.507 6.507 0 0 0-4.666-5.5c.123.181.24.365.353.552.714 1.192 1.436 2.874 1.58 4.948Z"></path> </svg> </template> <template id="issue-opened-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-issue-opened"> <path d="M8 9.5a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"></path><path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Z"></path> </svg> </template> <template id="device-mobile-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-device-mobile"> <path d="M3.75 0h8.5C13.216 0 14 .784 14 1.75v12.5A1.75 1.75 0 0 1 12.25 16h-8.5A1.75 1.75 0 0 1 2 14.25V1.75C2 .784 2.784 0 3.75 0ZM3.5 1.75v12.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25V1.75a.25.25 0 0 0-.25-.25h-8.5a.25.25 0 0 0-.25.25ZM8 13a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path> </svg> </template> <template id="package-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-package"> <path d="m8.878.392 5.25 3.045c.54.314.872.89.872 1.514v6.098a1.75 1.75 0 0 1-.872 1.514l-5.25 3.045a1.75 1.75 0 0 1-1.756 0l-5.25-3.045A1.75 1.75 0 0 1 1 11.049V4.951c0-.624.332-1.201.872-1.514L7.122.392a1.75 1.75 0 0 1 1.756 0ZM7.875 1.69l-4.63 2.685L8 7.133l4.755-2.758-4.63-2.685a.248.248 0 0 0-.25 0ZM2.5 5.677v5.372c0 .09.047.171.125.216l4.625 2.683V8.432Zm6.25 8.271 4.625-2.683a.25.25 0 0 0 .125-.216V5.677L8.75 8.432Z"></path> </svg> </template> <template id="credit-card-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-credit-card"> <path d="M10.75 9a.75.75 0 0 0 0 1.5h1.5a.75.75 0 0 0 0-1.5h-1.5Z"></path><path d="M0 3.75C0 2.784.784 2 1.75 2h12.5c.966 0 1.75.784 1.75 1.75v8.5A1.75 1.75 0 0 1 14.25 14H1.75A1.75 1.75 0 0 1 0 12.25ZM14.5 6.5h-13v5.75c0 .138.112.25.25.25h12.5a.25.25 0 0 0 .25-.25Zm0-2.75a.25.25 0 0 0-.25-.25H1.75a.25.25 0 0 0-.25.25V5h13Z"></path> </svg> </template> <template id="play-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-play"> <path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Zm4.879-2.773 4.264 2.559a.25.25 0 0 1 0 .428l-4.264 2.559A.25.25 0 0 1 6 10.559V5.442a.25.25 0 0 1 .379-.215Z"></path> </svg> </template> <template id="gift-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-gift"> <path d="M2 2.75A2.75 2.75 0 0 1 4.75 0c.983 0 1.873.42 2.57 1.232.268.318.497.668.68 1.042.183-.375.411-.725.68-1.044C9.376.42 10.266 0 11.25 0a2.75 2.75 0 0 1 2.45 4h.55c.966 0 1.75.784 1.75 1.75v2c0 .698-.409 1.301-1 1.582v4.918A1.75 1.75 0 0 1 13.25 16H2.75A1.75 1.75 0 0 1 1 14.25V9.332C.409 9.05 0 8.448 0 7.75v-2C0 4.784.784 4 1.75 4h.55c-.192-.375-.3-.8-.3-1.25ZM7.25 9.5H2.5v4.75c0 .138.112.25.25.25h4.5Zm1.5 0v5h4.5a.25.25 0 0 0 .25-.25V9.5Zm0-4V8h5.5a.25.25 0 0 0 .25-.25v-2a.25.25 0 0 0-.25-.25Zm-7 0a.25.25 0 0 0-.25.25v2c0 .138.112.25.25.25h5.5V5.5h-5.5Zm3-4a1.25 1.25 0 0 0 0 2.5h2.309c-.233-.818-.542-1.401-.878-1.793-.43-.502-.915-.707-1.431-.707ZM8.941 4h2.309a1.25 1.25 0 0 0 0-2.5c-.516 0-1 .205-1.43.707-.337.392-.646.975-.879 1.793Z"></path> </svg> </template> <template id="code-square-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-code-square"> <path d="M0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v12.5A1.75 1.75 0 0 1 14.25 16H1.75A1.75 1.75 0 0 1 0 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h12.5a.25.25 0 0 0 .25-.25V1.75a.25.25 0 0 0-.25-.25Zm7.47 3.97a.75.75 0 0 1 1.06 0l2 2a.75.75 0 0 1 0 1.06l-2 2a.749.749 0 0 1-1.275-.326.749.749 0 0 1 .215-.734L10.69 8 9.22 6.53a.75.75 0 0 1 0-1.06ZM6.78 6.53 5.31 8l1.47 1.47a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215l-2-2a.75.75 0 0 1 0-1.06l2-2a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042Z"></path> </svg> </template> <template id="device-desktop-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-device-desktop"> <path d="M14.25 1c.966 0 1.75.784 1.75 1.75v7.5A1.75 1.75 0 0 1 14.25 12h-3.727c.099 1.041.52 1.872 1.292 2.757A.752.752 0 0 1 11.25 16h-6.5a.75.75 0 0 1-.565-1.243c.772-.885 1.192-1.716 1.292-2.757H1.75A1.75 1.75 0 0 1 0 10.25v-7.5C0 1.784.784 1 1.75 1ZM1.75 2.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h12.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25ZM9.018 12H6.982a5.72 5.72 0 0 1-.765 2.5h3.566a5.72 5.72 0 0 1-.765-2.5Z"></path> </svg> </template> <div class="position-relative"> <ul role="listbox" class="ActionListWrap QueryBuilder-ListWrap" aria-label="Suggestions" data-action=" combobox-commit:query-builder#comboboxCommit mousedown:query-builder#resultsMousedown " data-target="query-builder.resultsList" data-persist-list=false id="query-builder-test-results" ></ul> </div> <div class="FormControl-inlineValidation" id="validation-e79781c6-547d-4ef8-ac8f-c6b0ea925bbd" hidden="hidden"> <span class="FormControl-inlineValidation--visual"> <svg aria-hidden="true" height="12" viewBox="0 0 12 12" version="1.1" width="12" data-view-component="true" class="octicon octicon-alert-fill"> <path d="M4.855.708c.5-.896 1.79-.896 2.29 0l4.675 8.351a1.312 1.312 0 0 1-1.146 1.954H1.33A1.313 1.313 0 0 1 .183 9.058ZM7 7V3H5v4Zm-1 3a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z"></path> </svg> </span> <span></span> </div> </div> <div data-target="query-builder.screenReaderFeedback" aria-live="polite" aria-atomic="true" class="sr-only"></div> </query-builder></form> <div class="d-flex flex-row color-fg-muted px-3 text-small color-bg-default search-feedback-prompt"> <a target="_blank" href="https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax" data-view-component="true" class="Link color-fg-accent text-normal ml-2">Search syntax tips</a> <div class="d-flex flex-1"></div> </div> </div> </div> </div> </modal-dialog></div> </div> <div data-action="click:qbsearch-input#retract" class="dark-backdrop position-fixed" hidden data-target="qbsearch-input.darkBackdrop"></div> <div class="color-fg-default"> <dialog-helper> <dialog data-target="qbsearch-input.feedbackDialog" data-action="close:qbsearch-input#handleDialogClose cancel:qbsearch-input#handleDialogClose" id="feedback-dialog" aria-modal="true" aria-labelledby="feedback-dialog-title" aria-describedby="feedback-dialog-description" data-view-component="true" class="Overlay Overlay-whenNarrow Overlay--size-medium Overlay--motion-scaleFade Overlay--disableScroll"> <div data-view-component="true" class="Overlay-header"> <div class="Overlay-headerContentWrap"> <div class="Overlay-titleWrap"> <h1 class="Overlay-title " id="feedback-dialog-title"> Provide feedback </h1> </div> <div class="Overlay-actionWrap"> <button data-close-dialog-id="feedback-dialog" aria-label="Close" type="button" data-view-component="true" class="close-button Overlay-closeButton"><svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-x"> <path d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l3.22 3.22a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-3.22 3.22a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z"></path> </svg></button> </div> </div> </div> <scrollable-region data-labelled-by="feedback-dialog-title"> <div data-view-component="true" class="Overlay-body"> <!-- '"` --><!-- </textarea></xmp> --></option></form><form id="code-search-feedback-form" data-turbo="false" action="/search/feedback" accept-charset="UTF-8" method="post"><input type="hidden" data-csrf="true" name="authenticity_token" value="Ekxk2aVB7HZBfZUg0b4NhLybBe2pOK9DrotA8QQVLN0Xfy4xPt0Qrluz2379f/NMaGH9KV6rG8KlML+xUJJp8A==" /> <p>We read every piece of feedback, and take your input very seriously.</p> <textarea name="feedback" class="form-control width-full mb-2" style="height: 120px" id="feedback"></textarea> <input name="include_email" id="include_email" aria-label="Include my email address so I can be contacted" class="form-control mr-2" type="checkbox"> <label for="include_email" style="font-weight: normal">Include my email address so I can be contacted</label> </form></div> </scrollable-region> <div data-view-component="true" class="Overlay-footer Overlay-footer--alignEnd"> <button data-close-dialog-id="feedback-dialog" type="button" data-view-component="true" class="btn"> Cancel </button> <button form="code-search-feedback-form" data-action="click:qbsearch-input#submitFeedback" type="submit" data-view-component="true" class="btn-primary btn"> Submit feedback </button> </div> </dialog></dialog-helper> <custom-scopes data-target="qbsearch-input.customScopesManager"> <dialog-helper> <dialog data-target="custom-scopes.customScopesModalDialog" data-action="close:qbsearch-input#handleDialogClose cancel:qbsearch-input#handleDialogClose" id="custom-scopes-dialog" aria-modal="true" aria-labelledby="custom-scopes-dialog-title" aria-describedby="custom-scopes-dialog-description" data-view-component="true" class="Overlay Overlay-whenNarrow Overlay--size-medium Overlay--motion-scaleFade Overlay--disableScroll"> <div data-view-component="true" class="Overlay-header Overlay-header--divided"> <div class="Overlay-headerContentWrap"> <div class="Overlay-titleWrap"> <h1 class="Overlay-title " id="custom-scopes-dialog-title"> Saved searches </h1> <h2 id="custom-scopes-dialog-description" class="Overlay-description">Use saved searches to filter your results more quickly</h2> </div> <div class="Overlay-actionWrap"> <button data-close-dialog-id="custom-scopes-dialog" aria-label="Close" type="button" data-view-component="true" class="close-button Overlay-closeButton"><svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-x"> <path d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l3.22 3.22a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-3.22 3.22a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z"></path> </svg></button> </div> </div> </div> <scrollable-region data-labelled-by="custom-scopes-dialog-title"> <div data-view-component="true" class="Overlay-body"> <div data-target="custom-scopes.customScopesModalDialogFlash"></div> <div hidden class="create-custom-scope-form" data-target="custom-scopes.createCustomScopeForm"> <!-- '"` --><!-- </textarea></xmp> --></option></form><form id="custom-scopes-dialog-form" data-turbo="false" action="/search/custom_scopes" accept-charset="UTF-8" method="post"><input type="hidden" data-csrf="true" name="authenticity_token" value="ejVPT8jjqDA+B8sMBRueoDnHzyVM/u5IsUubBGslJDTaWqNGNdJTe3ceh8K3yv+Ld4vgwnZK2dDRacP5C6mdVw==" /> <div data-target="custom-scopes.customScopesModalDialogFlash"></div> <input type="hidden" id="custom_scope_id" name="custom_scope_id" data-target="custom-scopes.customScopesIdField"> <div class="form-group"> <label for="custom_scope_name">Name</label> <auto-check src="/search/custom_scopes/check_name" required only-validate-on-blur="false"> <input type="text" name="custom_scope_name" id="custom_scope_name" data-target="custom-scopes.customScopesNameField" class="form-control" autocomplete="off" placeholder="github-ruby" required maxlength="50"> <input type="hidden" data-csrf="true" value="TVn56K+0Tk50gcK3P8z5jHLhYy5bz6epuu6SmJ6uH+otAu4+BFd1q8nXqqppn/fxUNUOrZGwjrgU7HyFDR78kA==" /> </auto-check> </div> <div class="form-group"> <label for="custom_scope_query">Query</label> <input type="text" name="custom_scope_query" id="custom_scope_query" data-target="custom-scopes.customScopesQueryField" class="form-control" autocomplete="off" placeholder="(repo:mona/a OR repo:mona/b) AND lang:python" required maxlength="500"> </div> <p class="text-small color-fg-muted"> To see all available qualifiers, see our <a class="Link--inTextBlock" href="https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax">documentation</a>. </p> </form> </div> <div data-target="custom-scopes.manageCustomScopesForm"> <div data-target="custom-scopes.list"></div> </div> </div> </scrollable-region> <div data-view-component="true" class="Overlay-footer Overlay-footer--alignEnd Overlay-footer--divided"> <button data-action="click:custom-scopes#customScopesCancel" type="button" data-view-component="true" class="btn"> Cancel </button> <button form="custom-scopes-dialog-form" data-action="click:custom-scopes#customScopesSubmit" data-target="custom-scopes.customScopesSubmitButton" type="submit" data-view-component="true" class="btn-primary btn"> Create saved search </button> </div> </dialog></dialog-helper> </custom-scopes> </div> </qbsearch-input> <div class="position-relative HeaderMenu-link-wrap d-lg-inline-block"> <a href="/login?return_to=https%3A%2F%2Fgithub.com%2Fgoogle%2Fcel-spec%2Fblob%2Fmaster%2Fdoc%2Flangdef.md" class="HeaderMenu-link HeaderMenu-link--sign-in HeaderMenu-button flex-shrink-0 no-underline d-none d-lg-inline-flex border border-lg-0 rounded rounded-lg-0 px-2 py-1" style="margin-left: 12px;" data-hydro-click="{&quot;event_type&quot;:&quot;authentication.click&quot;,&quot;payload&quot;:{&quot;location_in_page&quot;:&quot;site header menu&quot;,&quot;repository_id&quot;:null,&quot;auth_type&quot;:&quot;SIGN_UP&quot;,&quot;originating_url&quot;:&quot;https://github.com/google/cel-spec/blob/master/doc/langdef.md&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="13775a14edcea7e1ce2688c156695c06fe9bd645faab95e63cdcbb83e1711c33" data-analytics-event="{&quot;category&quot;:&quot;Marketing nav&quot;,&quot;action&quot;:&quot;click to go to homepage&quot;,&quot;label&quot;:&quot;ref_page:Marketing;ref_cta:Sign in;ref_loc:Header&quot;}" > Sign in </a> </div> <a href="/signup?ref_cta=Sign+up&amp;ref_loc=header+logged+out&amp;ref_page=%2F%3Cuser-name%3E%2F%3Crepo-name%3E%2Fblob%2Fshow&amp;source=header-repo&amp;source_repo=google%2Fcel-spec" class="HeaderMenu-link HeaderMenu-link--sign-up HeaderMenu-button flex-shrink-0 d-flex d-lg-inline-flex no-underline border color-border-default rounded px-2 py-1" data-hydro-click="{&quot;event_type&quot;:&quot;authentication.click&quot;,&quot;payload&quot;:{&quot;location_in_page&quot;:&quot;site header menu&quot;,&quot;repository_id&quot;:null,&quot;auth_type&quot;:&quot;SIGN_UP&quot;,&quot;originating_url&quot;:&quot;https://github.com/google/cel-spec/blob/master/doc/langdef.md&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="13775a14edcea7e1ce2688c156695c06fe9bd645faab95e63cdcbb83e1711c33" data-analytics-event="{&quot;category&quot;:&quot;Sign up&quot;,&quot;action&quot;:&quot;click to sign up for account&quot;,&quot;label&quot;:&quot;ref_page:/&lt;user-name&gt;/&lt;repo-name&gt;/blob/show;ref_cta:Sign up;ref_loc:header logged out&quot;}" > Sign up </a> <button type="button" class="sr-only js-header-menu-focus-trap d-block d-lg-none">Reseting focus</button> </div> </div> </div> </div> </header> <div hidden="hidden" data-view-component="true" class="js-stale-session-flash stale-session-flash flash flash-warn flash-full"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-alert"> <path d="M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path> </svg> <span class="js-stale-session-flash-signed-in" hidden>You signed in with another tab or window. <a class="Link--inTextBlock" href="">Reload</a> to refresh your session.</span> <span class="js-stale-session-flash-signed-out" hidden>You signed out in another tab or window. <a class="Link--inTextBlock" href="">Reload</a> to refresh your session.</span> <span class="js-stale-session-flash-switched" hidden>You switched accounts on another tab or window. <a class="Link--inTextBlock" href="">Reload</a> to refresh your session.</span> <button id="icon-button-8b7a197e-07d7-4ba4-a87c-3120fa4a134f" aria-labelledby="tooltip-e7f2ac28-6181-4138-a671-cd1868ae6c2c" type="button" data-view-component="true" class="Button Button--iconOnly Button--invisible Button--medium flash-close js-flash-close"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-x Button-visual"> <path d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l3.22 3.22a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-3.22 3.22a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z"></path> </svg> </button><tool-tip id="tooltip-e7f2ac28-6181-4138-a671-cd1868ae6c2c" for="icon-button-8b7a197e-07d7-4ba4-a87c-3120fa4a134f" popover="manual" data-direction="s" data-type="label" data-view-component="true" class="sr-only position-absolute">Dismiss alert</tool-tip> </div> </div> <div id="start-of-content" class="show-on-focus"></div> <div id="js-flash-container" class="flash-container" data-turbo-replace> <template class="js-flash-template"> <div class="flash flash-full {{ className }}"> <div > <button autofocus class="flash-close js-flash-close" type="button" aria-label="Dismiss this message"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-x"> <path d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l3.22 3.22a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-3.22 3.22a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z"></path> </svg> </button> <div aria-atomic="true" role="alert" class="js-flash-alert"> <div>{{ message }}</div> </div> </div> </div> </template> </div> <div class="application-main " data-commit-hovercards-enabled data-discussion-hovercards-enabled data-issue-and-pr-hovercards-enabled data-project-hovercards-enabled > <div itemscope itemtype="http://schema.org/SoftwareSourceCode" class=""> <main id="js-repo-pjax-container" > <div id="repository-container-header" class="pt-3 hide-full-screen" style="background-color: var(--page-header-bgColor, var(--color-page-header-bg));" data-turbo-replace> <div class="d-flex flex-nowrap flex-justify-end mb-3 px-3 px-lg-5" style="gap: 1rem;"> <div class="flex-auto min-width-0 width-fit"> <div class=" d-flex flex-wrap flex-items-center wb-break-word f3 text-normal"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-repo color-fg-muted mr-2"> <path d="M2 2.5A2.5 2.5 0 0 1 4.5 0h8.75a.75.75 0 0 1 .75.75v12.5a.75.75 0 0 1-.75.75h-2.5a.75.75 0 0 1 0-1.5h1.75v-2h-8a1 1 0 0 0-.714 1.7.75.75 0 1 1-1.072 1.05A2.495 2.495 0 0 1 2 11.5Zm10.5-1h-8a1 1 0 0 0-1 1v6.708A2.486 2.486 0 0 1 4.5 9h8ZM5 12.25a.25.25 0 0 1 .25-.25h3.5a.25.25 0 0 1 .25.25v3.25a.25.25 0 0 1-.4.2l-1.45-1.087a.249.249 0 0 0-.3 0L5.4 15.7a.25.25 0 0 1-.4-.2Z"></path> </svg> <span class="author flex-self-stretch" itemprop="author"> <a class="url fn" rel="author" data-hovercard-type="organization" data-hovercard-url="/orgs/google/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="/google"> google </a> </span> <span class="mx-1 flex-self-stretch color-fg-muted">/</span> <strong itemprop="name" class="mr-2 flex-self-stretch"> <a data-pjax="#repo-content-pjax-container" data-turbo-frame="repo-content-turbo-frame" href="/google/cel-spec">cel-spec</a> </strong> <span></span><span class="Label Label--secondary v-align-middle mr-1">Public</span> </div> </div> <div id="repository-details-container" class="flex-shrink-0" data-turbo-replace style="max-width: 70%;"> <ul class="pagehead-actions flex-shrink-0 d-none d-md-inline" style="padding: 2px 0;"> <li> <a href="/login?return_to=%2Fgoogle%2Fcel-spec" rel="nofollow" id="repository-details-watch-button" data-hydro-click="{&quot;event_type&quot;:&quot;authentication.click&quot;,&quot;payload&quot;:{&quot;location_in_page&quot;:&quot;notification subscription menu watch&quot;,&quot;repository_id&quot;:null,&quot;auth_type&quot;:&quot;LOG_IN&quot;,&quot;originating_url&quot;:&quot;https://github.com/google/cel-spec/blob/master/doc/langdef.md&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="9ac961b179f8f873d6865b1dfe687c2ffc3ca5b551e333ec1df49d9b4e13bf0e" aria-label="You must be signed in to change notification settings" data-view-component="true" class="btn-sm btn"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-bell mr-2"> <path d="M8 16a2 2 0 0 0 1.985-1.75c.017-.137-.097-.25-.235-.25h-3.5c-.138 0-.252.113-.235.25A2 2 0 0 0 8 16ZM3 5a5 5 0 0 1 10 0v2.947c0 .05.015.098.042.139l1.703 2.555A1.519 1.519 0 0 1 13.482 13H2.518a1.516 1.516 0 0 1-1.263-2.36l1.703-2.554A.255.255 0 0 0 3 7.947Zm5-3.5A3.5 3.5 0 0 0 4.5 5v2.947c0 .346-.102.683-.294.97l-1.703 2.556a.017.017 0 0 0-.003.01l.001.006c0 .002.002.004.004.006l.006.004.007.001h10.964l.007-.001.006-.004.004-.006.001-.007a.017.017 0 0 0-.003-.01l-1.703-2.554a1.745 1.745 0 0 1-.294-.97V5A3.5 3.5 0 0 0 8 1.5Z"></path> </svg>Notifications </a> <tool-tip id="tooltip-9314d398-1a43-4372-a132-5e8c9c56340d" for="repository-details-watch-button" popover="manual" data-direction="s" data-type="description" data-view-component="true" class="sr-only position-absolute">You must be signed in to change notification settings</tool-tip> </li> <li> <a icon="repo-forked" id="fork-button" href="/login?return_to=%2Fgoogle%2Fcel-spec" rel="nofollow" data-hydro-click="{&quot;event_type&quot;:&quot;authentication.click&quot;,&quot;payload&quot;:{&quot;location_in_page&quot;:&quot;repo details fork button&quot;,&quot;repository_id&quot;:102390943,&quot;auth_type&quot;:&quot;LOG_IN&quot;,&quot;originating_url&quot;:&quot;https://github.com/google/cel-spec/blob/master/doc/langdef.md&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="028b49f00b81fb2c644158796b74d4a035522918870d1defbc7ae9016a935987" data-view-component="true" class="btn-sm btn"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-repo-forked mr-2"> <path d="M5 5.372v.878c0 .414.336.75.75.75h4.5a.75.75 0 0 0 .75-.75v-.878a2.25 2.25 0 1 1 1.5 0v.878a2.25 2.25 0 0 1-2.25 2.25h-1.5v2.128a2.251 2.251 0 1 1-1.5 0V8.5h-1.5A2.25 2.25 0 0 1 3.5 6.25v-.878a2.25 2.25 0 1 1 1.5 0ZM5 3.25a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Zm6.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm-3 8.75a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Z"></path> </svg>Fork <span id="repo-network-counter" data-pjax-replace="true" data-turbo-replace="true" title="236" data-view-component="true" class="Counter">236</span> </a> </li> <li> <div data-view-component="true" class="BtnGroup d-flex"> <a href="/login?return_to=%2Fgoogle%2Fcel-spec" rel="nofollow" data-hydro-click="{&quot;event_type&quot;:&quot;authentication.click&quot;,&quot;payload&quot;:{&quot;location_in_page&quot;:&quot;star button&quot;,&quot;repository_id&quot;:102390943,&quot;auth_type&quot;:&quot;LOG_IN&quot;,&quot;originating_url&quot;:&quot;https://github.com/google/cel-spec/blob/master/doc/langdef.md&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="6564db9421d9d36823d94e153d60cb24466672441a8795c881873c67ba32fdfc" aria-label="You must be signed in to star a repository" data-view-component="true" class="tooltipped tooltipped-sw btn-sm btn"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-star v-align-text-bottom d-inline-block mr-2"> <path d="M8 .25a.75.75 0 0 1 .673.418l1.882 3.815 4.21.612a.75.75 0 0 1 .416 1.279l-3.046 2.97.719 4.192a.751.751 0 0 1-1.088.791L8 12.347l-3.766 1.98a.75.75 0 0 1-1.088-.79l.72-4.194L.818 6.374a.75.75 0 0 1 .416-1.28l4.21-.611L7.327.668A.75.75 0 0 1 8 .25Zm0 2.445L6.615 5.5a.75.75 0 0 1-.564.41l-3.097.45 2.24 2.184a.75.75 0 0 1 .216.664l-.528 3.084 2.769-1.456a.75.75 0 0 1 .698 0l2.77 1.456-.53-3.084a.75.75 0 0 1 .216-.664l2.24-2.183-3.096-.45a.75.75 0 0 1-.564-.41L8 2.694Z"></path> </svg><span data-view-component="true" class="d-inline"> Star </span> <span id="repo-stars-counter-star" aria-label="3037 users starred this repository" data-singular-suffix="user starred this repository" data-plural-suffix="users starred this repository" data-turbo-replace="true" title="3,037" data-view-component="true" class="Counter js-social-count">3k</span> </a></div> </li> </ul> </div> </div> <div id="responsive-meta-container" data-turbo-replace> </div> <nav data-pjax="#js-repo-pjax-container" aria-label="Repository" data-view-component="true" class="js-repo-nav js-sidenav-container-pjax js-responsive-underlinenav overflow-hidden UnderlineNav px-3 px-md-4 px-lg-5"> <ul data-view-component="true" class="UnderlineNav-body list-style-none"> <li data-view-component="true" class="d-inline-flex"> <a id="code-tab" href="/google/cel-spec" data-tab-item="i0code-tab" data-selected-links="repo_source repo_downloads repo_commits repo_releases repo_tags repo_branches repo_packages repo_deployments repo_attestations /google/cel-spec" data-pjax="#repo-content-pjax-container" data-turbo-frame="repo-content-turbo-frame" data-hotkey="g c" data-analytics-event="{&quot;category&quot;:&quot;Underline navbar&quot;,&quot;action&quot;:&quot;Click tab&quot;,&quot;label&quot;:&quot;Code&quot;,&quot;target&quot;:&quot;UNDERLINE_NAV.TAB&quot;}" aria-current="page" data-view-component="true" class="UnderlineNav-item no-wrap js-responsive-underlinenav-item js-selected-navigation-item selected"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-code UnderlineNav-octicon d-none d-sm-inline"> <path d="m11.28 3.22 4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.749.749 0 0 1-1.275-.326.749.749 0 0 1 .215-.734L13.94 8l-3.72-3.72a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215Zm-6.56 0a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042L2.06 8l3.72 3.72a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L.47 8.53a.75.75 0 0 1 0-1.06Z"></path> </svg> <span data-content="Code">Code</span> <span id="code-repo-tab-count" data-pjax-replace="" data-turbo-replace="" title="Not available" data-view-component="true" class="Counter"></span> </a></li> <li data-view-component="true" class="d-inline-flex"> <a id="issues-tab" href="/google/cel-spec/issues" data-tab-item="i1issues-tab" data-selected-links="repo_issues repo_labels repo_milestones /google/cel-spec/issues" data-pjax="#repo-content-pjax-container" data-turbo-frame="repo-content-turbo-frame" data-hotkey="g i" data-analytics-event="{&quot;category&quot;:&quot;Underline navbar&quot;,&quot;action&quot;:&quot;Click tab&quot;,&quot;label&quot;:&quot;Issues&quot;,&quot;target&quot;:&quot;UNDERLINE_NAV.TAB&quot;}" data-view-component="true" class="UnderlineNav-item no-wrap js-responsive-underlinenav-item js-selected-navigation-item"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-issue-opened UnderlineNav-octicon d-none d-sm-inline"> <path d="M8 9.5a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"></path><path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Z"></path> </svg> <span data-content="Issues">Issues</span> <span id="issues-repo-tab-count" data-pjax-replace="" data-turbo-replace="" title="58" data-view-component="true" class="Counter">58</span> </a></li> <li data-view-component="true" class="d-inline-flex"> <a id="pull-requests-tab" href="/google/cel-spec/pulls" data-tab-item="i2pull-requests-tab" data-selected-links="repo_pulls checks /google/cel-spec/pulls" data-pjax="#repo-content-pjax-container" data-turbo-frame="repo-content-turbo-frame" data-hotkey="g p" data-analytics-event="{&quot;category&quot;:&quot;Underline navbar&quot;,&quot;action&quot;:&quot;Click tab&quot;,&quot;label&quot;:&quot;Pull requests&quot;,&quot;target&quot;:&quot;UNDERLINE_NAV.TAB&quot;}" data-view-component="true" class="UnderlineNav-item no-wrap js-responsive-underlinenav-item js-selected-navigation-item"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-git-pull-request UnderlineNav-octicon d-none d-sm-inline"> <path d="M1.5 3.25a2.25 2.25 0 1 1 3 2.122v5.256a2.251 2.251 0 1 1-1.5 0V5.372A2.25 2.25 0 0 1 1.5 3.25Zm5.677-.177L9.573.677A.25.25 0 0 1 10 .854V2.5h1A2.5 2.5 0 0 1 13.5 5v5.628a2.251 2.251 0 1 1-1.5 0V5a1 1 0 0 0-1-1h-1v1.646a.25.25 0 0 1-.427.177L7.177 3.427a.25.25 0 0 1 0-.354ZM3.75 2.5a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Zm0 9.5a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Zm8.25.75a.75.75 0 1 0 1.5 0 .75.75 0 0 0-1.5 0Z"></path> </svg> <span data-content="Pull requests">Pull requests</span> <span id="pull-requests-repo-tab-count" data-pjax-replace="" data-turbo-replace="" title="5" data-view-component="true" class="Counter">5</span> </a></li> <li data-view-component="true" class="d-inline-flex"> <a id="discussions-tab" href="/google/cel-spec/discussions" data-tab-item="i3discussions-tab" data-selected-links="repo_discussions /google/cel-spec/discussions" data-pjax="#repo-content-pjax-container" data-turbo-frame="repo-content-turbo-frame" data-hotkey="g g" data-analytics-event="{&quot;category&quot;:&quot;Underline navbar&quot;,&quot;action&quot;:&quot;Click tab&quot;,&quot;label&quot;:&quot;Discussions&quot;,&quot;target&quot;:&quot;UNDERLINE_NAV.TAB&quot;}" data-view-component="true" class="UnderlineNav-item no-wrap js-responsive-underlinenav-item js-selected-navigation-item"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-comment-discussion UnderlineNav-octicon d-none d-sm-inline"> <path d="M1.75 1h8.5c.966 0 1.75.784 1.75 1.75v5.5A1.75 1.75 0 0 1 10.25 10H7.061l-2.574 2.573A1.458 1.458 0 0 1 2 11.543V10h-.25A1.75 1.75 0 0 1 0 8.25v-5.5C0 1.784.784 1 1.75 1ZM1.5 2.75v5.5c0 .138.112.25.25.25h1a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h3.5a.25.25 0 0 0 .25-.25v-5.5a.25.25 0 0 0-.25-.25h-8.5a.25.25 0 0 0-.25.25Zm13 2a.25.25 0 0 0-.25-.25h-.5a.75.75 0 0 1 0-1.5h.5c.966 0 1.75.784 1.75 1.75v5.5A1.75 1.75 0 0 1 14.25 12H14v1.543a1.458 1.458 0 0 1-2.487 1.03L9.22 12.28a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215l2.22 2.22v-2.19a.75.75 0 0 1 .75-.75h1a.25.25 0 0 0 .25-.25Z"></path> </svg> <span data-content="Discussions">Discussions</span> <span id="discussions-repo-tab-count" data-pjax-replace="" data-turbo-replace="" title="Not available" data-view-component="true" class="Counter"></span> </a></li> <li data-view-component="true" class="d-inline-flex"> <a id="actions-tab" href="/google/cel-spec/actions" data-tab-item="i4actions-tab" data-selected-links="repo_actions /google/cel-spec/actions" data-pjax="#repo-content-pjax-container" data-turbo-frame="repo-content-turbo-frame" data-hotkey="g a" data-analytics-event="{&quot;category&quot;:&quot;Underline navbar&quot;,&quot;action&quot;:&quot;Click tab&quot;,&quot;label&quot;:&quot;Actions&quot;,&quot;target&quot;:&quot;UNDERLINE_NAV.TAB&quot;}" data-view-component="true" class="UnderlineNav-item no-wrap js-responsive-underlinenav-item js-selected-navigation-item"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-play UnderlineNav-octicon d-none d-sm-inline"> <path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Zm4.879-2.773 4.264 2.559a.25.25 0 0 1 0 .428l-4.264 2.559A.25.25 0 0 1 6 10.559V5.442a.25.25 0 0 1 .379-.215Z"></path> </svg> <span data-content="Actions">Actions</span> <span id="actions-repo-tab-count" data-pjax-replace="" data-turbo-replace="" title="Not available" data-view-component="true" class="Counter"></span> </a></li> <li data-view-component="true" class="d-inline-flex"> <a id="projects-tab" href="/google/cel-spec/projects" data-tab-item="i5projects-tab" data-selected-links="repo_projects new_repo_project repo_project /google/cel-spec/projects" data-pjax="#repo-content-pjax-container" data-turbo-frame="repo-content-turbo-frame" data-hotkey="g b" data-analytics-event="{&quot;category&quot;:&quot;Underline navbar&quot;,&quot;action&quot;:&quot;Click tab&quot;,&quot;label&quot;:&quot;Projects&quot;,&quot;target&quot;:&quot;UNDERLINE_NAV.TAB&quot;}" data-view-component="true" class="UnderlineNav-item no-wrap js-responsive-underlinenav-item js-selected-navigation-item"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-table UnderlineNav-octicon d-none d-sm-inline"> <path d="M0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v12.5A1.75 1.75 0 0 1 14.25 16H1.75A1.75 1.75 0 0 1 0 14.25ZM6.5 6.5v8h7.75a.25.25 0 0 0 .25-.25V6.5Zm8-1.5V1.75a.25.25 0 0 0-.25-.25H6.5V5Zm-13 1.5v7.75c0 .138.112.25.25.25H5v-8ZM5 5V1.5H1.75a.25.25 0 0 0-.25.25V5Z"></path> </svg> <span data-content="Projects">Projects</span> <span id="projects-repo-tab-count" data-pjax-replace="" data-turbo-replace="" title="0" hidden="hidden" data-view-component="true" class="Counter">0</span> </a></li> <li data-view-component="true" class="d-inline-flex"> <a id="wiki-tab" href="/google/cel-spec/wiki" data-tab-item="i6wiki-tab" data-selected-links="repo_wiki /google/cel-spec/wiki" data-pjax="#repo-content-pjax-container" data-turbo-frame="repo-content-turbo-frame" data-hotkey="g w" data-analytics-event="{&quot;category&quot;:&quot;Underline navbar&quot;,&quot;action&quot;:&quot;Click tab&quot;,&quot;label&quot;:&quot;Wiki&quot;,&quot;target&quot;:&quot;UNDERLINE_NAV.TAB&quot;}" data-view-component="true" class="UnderlineNav-item no-wrap js-responsive-underlinenav-item js-selected-navigation-item"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-book UnderlineNav-octicon d-none d-sm-inline"> <path d="M0 1.75A.75.75 0 0 1 .75 1h4.253c1.227 0 2.317.59 3 1.501A3.743 3.743 0 0 1 11.006 1h4.245a.75.75 0 0 1 .75.75v10.5a.75.75 0 0 1-.75.75h-4.507a2.25 2.25 0 0 0-1.591.659l-.622.621a.75.75 0 0 1-1.06 0l-.622-.621A2.25 2.25 0 0 0 5.258 13H.75a.75.75 0 0 1-.75-.75Zm7.251 10.324.004-5.073-.002-2.253A2.25 2.25 0 0 0 5.003 2.5H1.5v9h3.757a3.75 3.75 0 0 1 1.994.574ZM8.755 4.75l-.004 7.322a3.752 3.752 0 0 1 1.992-.572H14.5v-9h-3.495a2.25 2.25 0 0 0-2.25 2.25Z"></path> </svg> <span data-content="Wiki">Wiki</span> <span id="wiki-repo-tab-count" data-pjax-replace="" data-turbo-replace="" title="Not available" data-view-component="true" class="Counter"></span> </a></li> <li data-view-component="true" class="d-inline-flex"> <a id="security-tab" href="/google/cel-spec/security" data-tab-item="i7security-tab" data-selected-links="security overview alerts policy token_scanning code_scanning /google/cel-spec/security" data-pjax="#repo-content-pjax-container" data-turbo-frame="repo-content-turbo-frame" data-hotkey="g s" data-analytics-event="{&quot;category&quot;:&quot;Underline navbar&quot;,&quot;action&quot;:&quot;Click tab&quot;,&quot;label&quot;:&quot;Security&quot;,&quot;target&quot;:&quot;UNDERLINE_NAV.TAB&quot;}" data-view-component="true" class="UnderlineNav-item no-wrap js-responsive-underlinenav-item js-selected-navigation-item"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-shield UnderlineNav-octicon d-none d-sm-inline"> <path d="M7.467.133a1.748 1.748 0 0 1 1.066 0l5.25 1.68A1.75 1.75 0 0 1 15 3.48V7c0 1.566-.32 3.182-1.303 4.682-.983 1.498-2.585 2.813-5.032 3.855a1.697 1.697 0 0 1-1.33 0c-2.447-1.042-4.049-2.357-5.032-3.855C1.32 10.182 1 8.566 1 7V3.48a1.75 1.75 0 0 1 1.217-1.667Zm.61 1.429a.25.25 0 0 0-.153 0l-5.25 1.68a.25.25 0 0 0-.174.238V7c0 1.358.275 2.666 1.057 3.86.784 1.194 2.121 2.34 4.366 3.297a.196.196 0 0 0 .154 0c2.245-.956 3.582-2.104 4.366-3.298C13.225 9.666 13.5 8.36 13.5 7V3.48a.251.251 0 0 0-.174-.237l-5.25-1.68ZM8.75 4.75v3a.75.75 0 0 1-1.5 0v-3a.75.75 0 0 1 1.5 0ZM9 10.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path> </svg> <span data-content="Security">Security</span> <include-fragment src="/google/cel-spec/security/overall-count" accept="text/fragment+html"></include-fragment> </a></li> <li data-view-component="true" class="d-inline-flex"> <a id="insights-tab" href="/google/cel-spec/pulse" data-tab-item="i8insights-tab" data-selected-links="repo_graphs repo_contributors dependency_graph dependabot_updates pulse people community /google/cel-spec/pulse" data-pjax="#repo-content-pjax-container" data-turbo-frame="repo-content-turbo-frame" data-analytics-event="{&quot;category&quot;:&quot;Underline navbar&quot;,&quot;action&quot;:&quot;Click tab&quot;,&quot;label&quot;:&quot;Insights&quot;,&quot;target&quot;:&quot;UNDERLINE_NAV.TAB&quot;}" data-view-component="true" class="UnderlineNav-item no-wrap js-responsive-underlinenav-item js-selected-navigation-item"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-graph UnderlineNav-octicon d-none d-sm-inline"> <path d="M1.5 1.75V13.5h13.75a.75.75 0 0 1 0 1.5H.75a.75.75 0 0 1-.75-.75V1.75a.75.75 0 0 1 1.5 0Zm14.28 2.53-5.25 5.25a.75.75 0 0 1-1.06 0L7 7.06 4.28 9.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.25-3.25a.75.75 0 0 1 1.06 0L10 7.94l4.72-4.72a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042Z"></path> </svg> <span data-content="Insights">Insights</span> <span id="insights-repo-tab-count" data-pjax-replace="" data-turbo-replace="" title="Not available" data-view-component="true" class="Counter"></span> </a></li> </ul> <div style="visibility:hidden;" data-view-component="true" class="UnderlineNav-actions js-responsive-underlinenav-overflow position-absolute pr-3 pr-md-4 pr-lg-5 right-0"> <action-menu data-select-variant="none" data-view-component="true"> <focus-group direction="vertical" mnemonics retain> <button id="action-menu-4e17d689-7bbf-46c6-a43d-8af70406926d-button" popovertarget="action-menu-4e17d689-7bbf-46c6-a43d-8af70406926d-overlay" aria-controls="action-menu-4e17d689-7bbf-46c6-a43d-8af70406926d-list" aria-haspopup="true" aria-labelledby="tooltip-8b56a905-3277-4f42-bf1e-af07160e7df2" type="button" data-view-component="true" class="Button Button--iconOnly Button--secondary Button--medium UnderlineNav-item"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-kebab-horizontal Button-visual"> <path d="M8 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3ZM1.5 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Zm13 0a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"></path> </svg> </button><tool-tip id="tooltip-8b56a905-3277-4f42-bf1e-af07160e7df2" for="action-menu-4e17d689-7bbf-46c6-a43d-8af70406926d-button" popover="manual" data-direction="s" data-type="label" data-view-component="true" class="sr-only position-absolute">Additional navigation options</tool-tip> <anchored-position data-target="action-menu.overlay" id="action-menu-4e17d689-7bbf-46c6-a43d-8af70406926d-overlay" anchor="action-menu-4e17d689-7bbf-46c6-a43d-8af70406926d-button" align="start" side="outside-bottom" anchor-offset="normal" popover="auto" data-view-component="true"> <div data-view-component="true" class="Overlay Overlay--size-auto"> <div data-view-component="true" class="Overlay-body Overlay-body--paddingNone"> <action-list> <div data-view-component="true"> <ul aria-labelledby="action-menu-4e17d689-7bbf-46c6-a43d-8af70406926d-button" id="action-menu-4e17d689-7bbf-46c6-a43d-8af70406926d-list" role="menu" data-view-component="true" class="ActionListWrap--inset ActionListWrap"> <li hidden="hidden" data-menu-item="i0code-tab" data-targets="action-list.items" role="none" data-view-component="true" class="ActionListItem"> <a tabindex="-1" id="item-cf5c4170-23eb-49cc-9cd4-9c1a4afaf93a" href="/google/cel-spec" role="menuitem" data-view-component="true" class="ActionListContent ActionListContent--visual16"> <span class="ActionListItem-visual ActionListItem-visual--leading"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-code"> <path d="m11.28 3.22 4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.749.749 0 0 1-1.275-.326.749.749 0 0 1 .215-.734L13.94 8l-3.72-3.72a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215Zm-6.56 0a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042L2.06 8l3.72 3.72a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L.47 8.53a.75.75 0 0 1 0-1.06Z"></path> </svg> </span> <span data-view-component="true" class="ActionListItem-label"> Code </span> </a> </li> <li hidden="hidden" data-menu-item="i1issues-tab" data-targets="action-list.items" role="none" data-view-component="true" class="ActionListItem"> <a tabindex="-1" id="item-898ec9d1-98ef-4261-be71-b1bbfdc80659" href="/google/cel-spec/issues" role="menuitem" data-view-component="true" class="ActionListContent ActionListContent--visual16"> <span class="ActionListItem-visual ActionListItem-visual--leading"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-issue-opened"> <path d="M8 9.5a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"></path><path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Z"></path> </svg> </span> <span data-view-component="true" class="ActionListItem-label"> Issues </span> </a> </li> <li hidden="hidden" data-menu-item="i2pull-requests-tab" data-targets="action-list.items" role="none" data-view-component="true" class="ActionListItem"> <a tabindex="-1" id="item-9faea53f-5232-49ac-aa45-589310356d4d" href="/google/cel-spec/pulls" role="menuitem" data-view-component="true" class="ActionListContent ActionListContent--visual16"> <span class="ActionListItem-visual ActionListItem-visual--leading"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-git-pull-request"> <path d="M1.5 3.25a2.25 2.25 0 1 1 3 2.122v5.256a2.251 2.251 0 1 1-1.5 0V5.372A2.25 2.25 0 0 1 1.5 3.25Zm5.677-.177L9.573.677A.25.25 0 0 1 10 .854V2.5h1A2.5 2.5 0 0 1 13.5 5v5.628a2.251 2.251 0 1 1-1.5 0V5a1 1 0 0 0-1-1h-1v1.646a.25.25 0 0 1-.427.177L7.177 3.427a.25.25 0 0 1 0-.354ZM3.75 2.5a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Zm0 9.5a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Zm8.25.75a.75.75 0 1 0 1.5 0 .75.75 0 0 0-1.5 0Z"></path> </svg> </span> <span data-view-component="true" class="ActionListItem-label"> Pull requests </span> </a> </li> <li hidden="hidden" data-menu-item="i3discussions-tab" data-targets="action-list.items" role="none" data-view-component="true" class="ActionListItem"> <a tabindex="-1" id="item-16234ad3-fa03-46ff-842f-158db435d18a" href="/google/cel-spec/discussions" role="menuitem" data-view-component="true" class="ActionListContent ActionListContent--visual16"> <span class="ActionListItem-visual ActionListItem-visual--leading"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-comment-discussion"> <path d="M1.75 1h8.5c.966 0 1.75.784 1.75 1.75v5.5A1.75 1.75 0 0 1 10.25 10H7.061l-2.574 2.573A1.458 1.458 0 0 1 2 11.543V10h-.25A1.75 1.75 0 0 1 0 8.25v-5.5C0 1.784.784 1 1.75 1ZM1.5 2.75v5.5c0 .138.112.25.25.25h1a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h3.5a.25.25 0 0 0 .25-.25v-5.5a.25.25 0 0 0-.25-.25h-8.5a.25.25 0 0 0-.25.25Zm13 2a.25.25 0 0 0-.25-.25h-.5a.75.75 0 0 1 0-1.5h.5c.966 0 1.75.784 1.75 1.75v5.5A1.75 1.75 0 0 1 14.25 12H14v1.543a1.458 1.458 0 0 1-2.487 1.03L9.22 12.28a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215l2.22 2.22v-2.19a.75.75 0 0 1 .75-.75h1a.25.25 0 0 0 .25-.25Z"></path> </svg> </span> <span data-view-component="true" class="ActionListItem-label"> Discussions </span> </a> </li> <li hidden="hidden" data-menu-item="i4actions-tab" data-targets="action-list.items" role="none" data-view-component="true" class="ActionListItem"> <a tabindex="-1" id="item-ecf63924-6532-4300-a955-685c768957c8" href="/google/cel-spec/actions" role="menuitem" data-view-component="true" class="ActionListContent ActionListContent--visual16"> <span class="ActionListItem-visual ActionListItem-visual--leading"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-play"> <path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Zm4.879-2.773 4.264 2.559a.25.25 0 0 1 0 .428l-4.264 2.559A.25.25 0 0 1 6 10.559V5.442a.25.25 0 0 1 .379-.215Z"></path> </svg> </span> <span data-view-component="true" class="ActionListItem-label"> Actions </span> </a> </li> <li hidden="hidden" data-menu-item="i5projects-tab" data-targets="action-list.items" role="none" data-view-component="true" class="ActionListItem"> <a tabindex="-1" id="item-0a7593ab-0f23-4a23-816d-2f836feda63c" href="/google/cel-spec/projects" role="menuitem" data-view-component="true" class="ActionListContent ActionListContent--visual16"> <span class="ActionListItem-visual ActionListItem-visual--leading"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-table"> <path d="M0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v12.5A1.75 1.75 0 0 1 14.25 16H1.75A1.75 1.75 0 0 1 0 14.25ZM6.5 6.5v8h7.75a.25.25 0 0 0 .25-.25V6.5Zm8-1.5V1.75a.25.25 0 0 0-.25-.25H6.5V5Zm-13 1.5v7.75c0 .138.112.25.25.25H5v-8ZM5 5V1.5H1.75a.25.25 0 0 0-.25.25V5Z"></path> </svg> </span> <span data-view-component="true" class="ActionListItem-label"> Projects </span> </a> </li> <li hidden="hidden" data-menu-item="i6wiki-tab" data-targets="action-list.items" role="none" data-view-component="true" class="ActionListItem"> <a tabindex="-1" id="item-05a692b7-57e7-4b0e-9e7b-003620cb0c4c" href="/google/cel-spec/wiki" role="menuitem" data-view-component="true" class="ActionListContent ActionListContent--visual16"> <span class="ActionListItem-visual ActionListItem-visual--leading"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-book"> <path d="M0 1.75A.75.75 0 0 1 .75 1h4.253c1.227 0 2.317.59 3 1.501A3.743 3.743 0 0 1 11.006 1h4.245a.75.75 0 0 1 .75.75v10.5a.75.75 0 0 1-.75.75h-4.507a2.25 2.25 0 0 0-1.591.659l-.622.621a.75.75 0 0 1-1.06 0l-.622-.621A2.25 2.25 0 0 0 5.258 13H.75a.75.75 0 0 1-.75-.75Zm7.251 10.324.004-5.073-.002-2.253A2.25 2.25 0 0 0 5.003 2.5H1.5v9h3.757a3.75 3.75 0 0 1 1.994.574ZM8.755 4.75l-.004 7.322a3.752 3.752 0 0 1 1.992-.572H14.5v-9h-3.495a2.25 2.25 0 0 0-2.25 2.25Z"></path> </svg> </span> <span data-view-component="true" class="ActionListItem-label"> Wiki </span> </a> </li> <li hidden="hidden" data-menu-item="i7security-tab" data-targets="action-list.items" role="none" data-view-component="true" class="ActionListItem"> <a tabindex="-1" id="item-de186610-dc50-4a89-99ab-50a991f6e51c" href="/google/cel-spec/security" role="menuitem" data-view-component="true" class="ActionListContent ActionListContent--visual16"> <span class="ActionListItem-visual ActionListItem-visual--leading"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-shield"> <path d="M7.467.133a1.748 1.748 0 0 1 1.066 0l5.25 1.68A1.75 1.75 0 0 1 15 3.48V7c0 1.566-.32 3.182-1.303 4.682-.983 1.498-2.585 2.813-5.032 3.855a1.697 1.697 0 0 1-1.33 0c-2.447-1.042-4.049-2.357-5.032-3.855C1.32 10.182 1 8.566 1 7V3.48a1.75 1.75 0 0 1 1.217-1.667Zm.61 1.429a.25.25 0 0 0-.153 0l-5.25 1.68a.25.25 0 0 0-.174.238V7c0 1.358.275 2.666 1.057 3.86.784 1.194 2.121 2.34 4.366 3.297a.196.196 0 0 0 .154 0c2.245-.956 3.582-2.104 4.366-3.298C13.225 9.666 13.5 8.36 13.5 7V3.48a.251.251 0 0 0-.174-.237l-5.25-1.68ZM8.75 4.75v3a.75.75 0 0 1-1.5 0v-3a.75.75 0 0 1 1.5 0ZM9 10.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path> </svg> </span> <span data-view-component="true" class="ActionListItem-label"> Security </span> </a> </li> <li hidden="hidden" data-menu-item="i8insights-tab" data-targets="action-list.items" role="none" data-view-component="true" class="ActionListItem"> <a tabindex="-1" id="item-a4ff1555-5d1d-42af-b130-58c0ed08d1bc" href="/google/cel-spec/pulse" role="menuitem" data-view-component="true" class="ActionListContent ActionListContent--visual16"> <span class="ActionListItem-visual ActionListItem-visual--leading"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-graph"> <path d="M1.5 1.75V13.5h13.75a.75.75 0 0 1 0 1.5H.75a.75.75 0 0 1-.75-.75V1.75a.75.75 0 0 1 1.5 0Zm14.28 2.53-5.25 5.25a.75.75 0 0 1-1.06 0L7 7.06 4.28 9.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.25-3.25a.75.75 0 0 1 1.06 0L10 7.94l4.72-4.72a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042Z"></path> </svg> </span> <span data-view-component="true" class="ActionListItem-label"> Insights </span> </a> </li> </ul> </div></action-list> </div> </div></anchored-position> </focus-group> </action-menu></div> </nav> </div> <turbo-frame id="repo-content-turbo-frame" target="_top" data-turbo-action="advance" class=""> <div id="repo-content-pjax-container" class="repository-content " > <react-app app-name="react-code-view" initial-path="/google/cel-spec/blob/master/doc/langdef.md" style="display: block; min-height: calc(100vh - 64px);" data-attempted-ssr="true" data-ssr="true" data-lazy="false" data-alternate="false" data-data-router-enabled="false" > <script type="application/json" data-target="react-app.embeddedData">{"payload":{"allShortcutsEnabled":false,"fileTree":{"doc":{"items":[{"name":"intro.md","path":"doc/intro.md","contentType":"file"},{"name":"langdef.md","path":"doc/langdef.md","contentType":"file"}],"totalCount":2},"":{"items":[{"name":"conformance","path":"conformance","contentType":"directory"},{"name":"doc","path":"doc","contentType":"directory"},{"name":"proto","path":"proto","contentType":"directory"},{"name":"tests","path":"tests","contentType":"directory"},{"name":".bazelversion","path":".bazelversion","contentType":"file"},{"name":".gitattributes","path":".gitattributes","contentType":"file"},{"name":".gitignore","path":".gitignore","contentType":"file"},{"name":"BUILD.bazel","path":"BUILD.bazel","contentType":"file"},{"name":"CODE_OF_CONDUCT.md","path":"CODE_OF_CONDUCT.md","contentType":"file"},{"name":"CONTRIBUTING.md","path":"CONTRIBUTING.md","contentType":"file"},{"name":"GOVERNANCE.md","path":"GOVERNANCE.md","contentType":"file"},{"name":"LICENSE","path":"LICENSE","contentType":"file"},{"name":"MAINTAINERS.md","path":"MAINTAINERS.md","contentType":"file"},{"name":"MODULE.bazel","path":"MODULE.bazel","contentType":"file"},{"name":"README.md","path":"README.md","contentType":"file"},{"name":"WORKSPACE","path":"WORKSPACE","contentType":"file"},{"name":"WORKSPACE.bzlmod","path":"WORKSPACE.bzlmod","contentType":"file"},{"name":"checked.pb.go","path":"checked.pb.go","contentType":"file"},{"name":"cloudbuild.yaml","path":"cloudbuild.yaml","contentType":"file"},{"name":"eval.pb.go","path":"eval.pb.go","contentType":"file"},{"name":"explain.pb.go","path":"explain.pb.go","contentType":"file"},{"name":"go.mod","path":"go.mod","contentType":"file"},{"name":"go.sum","path":"go.sum","contentType":"file"},{"name":"regen_go_proto.sh","path":"regen_go_proto.sh","contentType":"file"},{"name":"regen_go_proto_canonical_protos.sh","path":"regen_go_proto_canonical_protos.sh","contentType":"file"},{"name":"syntax.pb.go","path":"syntax.pb.go","contentType":"file"},{"name":"value.pb.go","path":"value.pb.go","contentType":"file"}],"totalCount":27}},"fileTreeProcessingTime":10.689752,"foldersToFetch":[],"repo":{"id":102390943,"defaultBranch":"master","name":"cel-spec","ownerLogin":"google","currentUserCanPush":false,"isFork":false,"isEmpty":false,"createdAt":"2017-09-04T18:33:35.000Z","ownerAvatar":"https://avatars.githubusercontent.com/u/1342004?v=4","public":true,"private":false,"isOrgOwned":true},"codeLineWrapEnabled":false,"symbolsExpanded":false,"treeExpanded":true,"refInfo":{"name":"master","listCacheKey":"v0:1739395832.0","canEdit":false,"refType":"branch","currentOid":"bfe4f8b06c29cc71b783819ef415e2e766606023"},"path":"doc/langdef.md","currentUser":null,"blob":{"rawLines":null,"stylingDirectives":null,"colorizedLines":null,"csv":null,"csvError":null,"dependabotInfo":{"showConfigurationBanner":false,"configFilePath":null,"networkDependabotPath":"/google/cel-spec/network/updates","dismissConfigurationNoticePath":"/settings/dismiss-notice/dependabot_configuration_notice","configurationNoticeDismissed":null},"displayName":"langdef.md","displayUrl":"https://github.com/google/cel-spec/blob/master/doc/langdef.md?raw=true","headerInfo":{"blobSize":"79.4 KB","deleteTooltip":"You must be signed in to make or propose changes","editTooltip":"You must be signed in to make or propose changes","ghDesktopPath":"https://desktop.github.com","isGitLfs":false,"onBranch":true,"shortPath":"1aebd17","siteNavLoginPath":"/login?return_to=https%3A%2F%2Fgithub.com%2Fgoogle%2Fcel-spec%2Fblob%2Fmaster%2Fdoc%2Flangdef.md","isCSV":false,"isRichtext":true,"toc":[{"level":1,"text":"Language Definition","anchor":"language-definition","htmlText":"Language Definition"},{"level":2,"text":"Contents","anchor":"contents","htmlText":"Contents"},{"level":2,"text":"Overview","anchor":"overview","htmlText":"Overview"},{"level":2,"text":"Syntax","anchor":"syntax","htmlText":"Syntax"},{"level":3,"text":"Name Resolution","anchor":"name-resolution","htmlText":"Name Resolution"},{"level":2,"text":"Values","anchor":"values","htmlText":"Values"},{"level":3,"text":"Numeric Values","anchor":"numeric-values","htmlText":"Numeric Values"},{"level":3,"text":"String and Bytes Values","anchor":"string-and-bytes-values","htmlText":"String and Bytes Values"},{"level":3,"text":"Aggregate Values","anchor":"aggregate-values","htmlText":"Aggregate Values"},{"level":3,"text":"Booleans and Null","anchor":"booleans-and-null","htmlText":"Booleans and Null"},{"level":3,"text":"Type Values","anchor":"type-values","htmlText":"Type Values"},{"level":3,"text":"Abstract Types","anchor":"abstract-types","htmlText":"Abstract Types"},{"level":3,"text":"Protocol Buffer Data Conversion","anchor":"protocol-buffer-data-conversion","htmlText":"Protocol Buffer Data Conversion"},{"level":3,"text":"Dynamic Values","anchor":"dynamic-values","htmlText":"Dynamic Values"},{"level":2,"text":"JSON Data Conversion","anchor":"json-data-conversion","htmlText":"JSON Data Conversion"},{"level":2,"text":"Gradual Type Checking","anchor":"gradual-type-checking","htmlText":"Gradual Type Checking"},{"level":2,"text":"Evaluation","anchor":"evaluation","htmlText":"Evaluation"},{"level":3,"text":"Evaluation Environment","anchor":"evaluation-environment","htmlText":"Evaluation Environment"},{"level":3,"text":"Runtime Errors","anchor":"runtime-errors","htmlText":"Runtime Errors"},{"level":3,"text":"Logical Operators","anchor":"logical-operators","htmlText":"Logical Operators"},{"level":3,"text":"Macros","anchor":"macros","htmlText":"Macros"},{"level":3,"text":"Field Selection","anchor":"field-selection","htmlText":"Field Selection"},{"level":2,"text":"Performance","anchor":"performance","htmlText":"Performance"},{"level":3,"text":"Abstract Sizes","anchor":"abstract-sizes","htmlText":"Abstract Sizes"},{"level":3,"text":"Time Complexity","anchor":"time-complexity","htmlText":"Time Complexity"},{"level":3,"text":"Space Complexity","anchor":"space-complexity","htmlText":"Space Complexity"},{"level":3,"text":"Macro Performance","anchor":"macro-performance","htmlText":"Macro Performance"},{"level":3,"text":"Performance Limits","anchor":"performance-limits","htmlText":"Performance Limits"},{"level":2,"text":"Functions","anchor":"functions","htmlText":"Functions"},{"level":3,"text":"Extension Functions","anchor":"extension-functions","htmlText":"Extension Functions"},{"level":3,"text":"Receiver Call Style","anchor":"receiver-call-style","htmlText":"Receiver Call Style"},{"level":2,"text":"Standard Definitions","anchor":"standard-definitions","htmlText":"Standard Definitions"},{"level":3,"text":"Equality","anchor":"equality","htmlText":"Equality"},{"level":4,"text":"Numbers","anchor":"numbers","htmlText":"Numbers"},{"level":4,"text":"Lists and Maps","anchor":"lists-and-maps","htmlText":"Lists and Maps"},{"level":4,"text":"Protocol Buffers","anchor":"protocol-buffers","htmlText":"Protocol Buffers"},{"level":3,"text":"Ordering","anchor":"ordering","htmlText":"Ordering"},{"level":3,"text":"Overflow","anchor":"overflow","htmlText":"Overflow"},{"level":3,"text":"Timezones","anchor":"timezones","htmlText":"Timezones"},{"level":3,"text":"Regular Expressions","anchor":"regular-expressions","htmlText":"Regular Expressions"},{"level":3,"text":"Standard Environment","anchor":"standard-environment","htmlText":"Standard Environment"},{"level":4,"text":"Presence and Comprehension Macros","anchor":"presence-and-comprehension-macros","htmlText":"Presence and Comprehension Macros"},{"level":4,"text":"Logical Operators","anchor":"logical-operators-1","htmlText":"Logical Operators"},{"level":4,"text":"Arithmetic Operators","anchor":"arithmetic-operators","htmlText":"Arithmetic Operators"},{"level":4,"text":"Comparison Operators","anchor":"comparison-operators","htmlText":"Comparison Operators"},{"level":4,"text":"List Operators","anchor":"list-operators","htmlText":"List Operators"},{"level":4,"text":"Map Operators","anchor":"map-operators","htmlText":"Map Operators"},{"level":4,"text":"Bytes Functions","anchor":"bytes-functions","htmlText":"Bytes Functions"},{"level":4,"text":"String Functions","anchor":"string-functions","htmlText":"String Functions"},{"level":4,"text":"Date/Time Functions","anchor":"datetime-functions","htmlText":"Date/Time Functions"},{"level":4,"text":"Types and Conversions","anchor":"types-and-conversions","htmlText":"Types and Conversions"},{"level":2,"text":"Appendix 1: Legacy Behavior","anchor":"appendix-1-legacy-behavior","htmlText":"Appendix 1: Legacy Behavior"},{"level":3,"text":"Homogeneous Equality","anchor":"homogeneous-equality","htmlText":"Homogeneous Equality"}],"lineInfo":{"truncatedLoc":"2208","truncatedSloc":"1698"},"mode":"file"},"image":false,"isCodeownersFile":null,"isPlain":false,"isValidLegacyIssueTemplate":false,"issueTemplate":null,"discussionTemplate":null,"language":"Markdown","languageID":222,"large":false,"planSupportInfo":{"repoIsFork":null,"repoOwnedByCurrentUser":null,"requestFullPath":"/google/cel-spec/blob/master/doc/langdef.md","showFreeOrgGatedFeatureMessage":null,"showPlanSupportBanner":null,"upgradeDataAttributes":null,"upgradePath":null},"publishBannersInfo":{"dismissActionNoticePath":"/settings/dismiss-notice/publish_action_from_dockerfile","releasePath":"/google/cel-spec/releases/new?marketplace=true","showPublishActionBanner":false},"rawBlobUrl":"https://github.com/google/cel-spec/raw/refs/heads/master/doc/langdef.md","renderImageOrRaw":false,"richText":"\u003carticle class=\"markdown-body entry-content container-lg\" itemprop=\"text\"\u003e\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch1 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eLanguage Definition\u003c/h1\u003e\u003ca id=\"user-content-language-definition\" class=\"anchor\" aria-label=\"Permalink: Language Definition\" href=\"#language-definition\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThis page constitutes the reference for CEL. For a gentle introduction, see\n\u003ca href=\"/google/cel-spec/blob/master/doc/intro.md\"\u003eIntro\u003c/a\u003e.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eContents\u003c/h2\u003e\u003ca id=\"user-content-contents\" class=\"anchor\" aria-label=\"Permalink: Contents\" href=\"#contents\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ca href=\"#overview\"\u003eOverview\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#syntax\"\u003eSyntax\u003c/a\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ca href=\"#name-resolution\"\u003eName Resolution\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#values\"\u003eValues\u003c/a\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ca href=\"#numeric-values\"\u003eNumeric Values\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#string-and-bytes-values\"\u003eString and Bytes Values\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#aggregate-values\"\u003eAggregate Values\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#booleans-and-null\"\u003eBooleans and Null\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#type-values\"\u003eType Values\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#abstract-types\"\u003eAbstract Types\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#protocol-buffer-data-conversion\"\u003eProtocol Buffer Data Conversion\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#dynamic-values\"\u003eDynamic Values\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#json-data-conversion\"\u003eJSON Data Conversion\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#gradual-type-checking\"\u003eGradual Type Checking\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#evaluation\"\u003eEvaluation\u003c/a\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ca href=\"#evaluation-environment\"\u003eEvaluation Environment\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#runtime-errors\"\u003eRuntime Errors\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#logical-operators\"\u003eLogical Operators\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#macros\"\u003eMacros\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#field-selection\"\u003eField Selection\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#performance\"\u003ePerformance\u003c/a\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ca href=\"#abstract-sizes\"\u003eAbstract Sizes\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#time-complexity\"\u003eTime Complexity\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#space-complexity\"\u003eSpace Complexity\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#macro-performance\"\u003eMacro Performance\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#performance-limits\"\u003ePerformance Limits\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#functions\"\u003eFunctions\u003c/a\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ca href=\"#extension-functions\"\u003eExtension Functions\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#receiver-call-style\"\u003eReceiver Call Style\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#standard-definitions\"\u003eStandard Definitions\u003c/a\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ca href=\"#equality\"\u003eEquality\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#ordering\"\u003eOrdering\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#overflow\"\u003eOverflow\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#timezones\"\u003eTimezones\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#regular-expressions\"\u003eRegular Expressions\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#standard-environment\"\u003eStandard Environment\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#appendix-1-legacy-behavior\"\u003eAppendix 1: Legacy Behavior\u003c/a\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ca href=\"#enums-as-ints\"\u003eEnums as Ints\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eOverview\u003c/h2\u003e\u003ca id=\"user-content-overview\" class=\"anchor\" aria-label=\"Permalink: Overview\" href=\"#overview\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eIn the taxonomy of programming languages, CEL is:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003cstrong\u003ememory-safe:\u003c/strong\u003e programs cannot access unrelated memory, such as\nout-of-bounds array indexes or use-after-free pointer dereferences;\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eside-effect-free:\u003c/strong\u003e a CEL program only computes an output from its inputs;\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eterminating:\u003c/strong\u003e CEL programs cannot loop forever;\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003estrongly-typed:\u003c/strong\u003e values have a well-defined type, and operators and\nfunctions check that their arguments have the expected types;\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003edynamically-typed:\u003c/strong\u003e types are associated with values, not with variables\nor expressions, and type safety is enforced at runtime;\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003egradually-typed:\u003c/strong\u003e an optional type-checking phase before runtime can\ndetect and reject some programs which would violate type constraints.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eSyntax\u003c/h2\u003e\u003ca id=\"user-content-syntax\" class=\"anchor\" aria-label=\"Permalink: Syntax\" href=\"#syntax\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThe grammar of CEL is defined below, using \u003ccode\u003e|\u003c/code\u003e for alternatives, \u003ccode\u003e[]\u003c/code\u003e for\noptional, \u003ccode\u003e{}\u003c/code\u003e for repeated, and \u003ccode\u003e()\u003c/code\u003e for grouping.\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"Expr = ConditionalOr [\u0026quot;?\u0026quot; ConditionalOr \u0026quot;:\u0026quot; Expr] ;\nConditionalOr = [ConditionalOr \u0026quot;||\u0026quot;] ConditionalAnd ;\nConditionalAnd = [ConditionalAnd \u0026quot;\u0026amp;\u0026amp;\u0026quot;] Relation ;\nRelation = [Relation Relop] Addition ;\nRelop = \u0026quot;\u0026lt;\u0026quot; | \u0026quot;\u0026lt;=\u0026quot; | \u0026quot;\u0026gt;=\u0026quot; | \u0026quot;\u0026gt;\u0026quot; | \u0026quot;==\u0026quot; | \u0026quot;!=\u0026quot; | \u0026quot;in\u0026quot; ;\nAddition = [Addition (\u0026quot;+\u0026quot; | \u0026quot;-\u0026quot;)] Multiplication ;\nMultiplication = [Multiplication (\u0026quot;*\u0026quot; | \u0026quot;/\u0026quot; | \u0026quot;%\u0026quot;)] Unary ;\nUnary = Member\n | \u0026quot;!\u0026quot; {\u0026quot;!\u0026quot;} Member\n | \u0026quot;-\u0026quot; {\u0026quot;-\u0026quot;} Member\n ;\nMember = Primary\n | Member \u0026quot;.\u0026quot; IDENT [\u0026quot;(\u0026quot; [ExprList] \u0026quot;)\u0026quot;]\n | Member \u0026quot;[\u0026quot; Expr \u0026quot;]\u0026quot;\n ;\nPrimary = [\u0026quot;.\u0026quot;] IDENT [\u0026quot;(\u0026quot; [ExprList] \u0026quot;)\u0026quot;]\n | \u0026quot;(\u0026quot; Expr \u0026quot;)\u0026quot;\n | \u0026quot;[\u0026quot; [ExprList] [\u0026quot;,\u0026quot;] \u0026quot;]\u0026quot;\n | \u0026quot;{\u0026quot; [MapInits] [\u0026quot;,\u0026quot;] \u0026quot;}\u0026quot;\n | [\u0026quot;.\u0026quot;] IDENT { \u0026quot;.\u0026quot; IDENT } \u0026quot;{\u0026quot; [FieldInits] [\u0026quot;,\u0026quot;] \u0026quot;}\u0026quot;\n | LITERAL\n ;\nExprList = Expr {\u0026quot;,\u0026quot; Expr} ;\nFieldInits = IDENT \u0026quot;:\u0026quot; Expr {\u0026quot;,\u0026quot; IDENT \u0026quot;:\u0026quot; Expr} ;\nMapInits = Expr \u0026quot;:\u0026quot; Expr {\u0026quot;,\u0026quot; Expr \u0026quot;:\u0026quot; Expr} ;\"\u003e\u003cpre lang=\"grammar\" class=\"notranslate\"\u003e\u003ccode\u003eExpr = ConditionalOr [\"?\" ConditionalOr \":\" Expr] ;\nConditionalOr = [ConditionalOr \"||\"] ConditionalAnd ;\nConditionalAnd = [ConditionalAnd \"\u0026amp;\u0026amp;\"] Relation ;\nRelation = [Relation Relop] Addition ;\nRelop = \"\u0026lt;\" | \"\u0026lt;=\" | \"\u0026gt;=\" | \"\u0026gt;\" | \"==\" | \"!=\" | \"in\" ;\nAddition = [Addition (\"+\" | \"-\")] Multiplication ;\nMultiplication = [Multiplication (\"*\" | \"/\" | \"%\")] Unary ;\nUnary = Member\n | \"!\" {\"!\"} Member\n | \"-\" {\"-\"} Member\n ;\nMember = Primary\n | Member \".\" IDENT [\"(\" [ExprList] \")\"]\n | Member \"[\" Expr \"]\"\n ;\nPrimary = [\".\"] IDENT [\"(\" [ExprList] \")\"]\n | \"(\" Expr \")\"\n | \"[\" [ExprList] [\",\"] \"]\"\n | \"{\" [MapInits] [\",\"] \"}\"\n | [\".\"] IDENT { \".\" IDENT } \"{\" [FieldInits] [\",\"] \"}\"\n | LITERAL\n ;\nExprList = Expr {\",\" Expr} ;\nFieldInits = IDENT \":\" Expr {\",\" IDENT \":\" Expr} ;\nMapInits = Expr \":\" Expr {\",\" Expr \":\" Expr} ;\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eImplementations are required to support at least:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e24-32 repetitions of repeating rules, i.e.:\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e32 terms separated by \u003ccode\u003e||\u003c/code\u003e in a row;\u003c/li\u003e\n\u003cli\u003e32 terms separated by \u003ccode\u003e\u0026amp;\u0026amp;\u003c/code\u003e in a row;\u003c/li\u003e\n\u003cli\u003e32 function call arguments;\u003c/li\u003e\n\u003cli\u003elist literals with 32 elements;\u003c/li\u003e\n\u003cli\u003emap or message literals with 32 fields;\u003c/li\u003e\n\u003cli\u003e24 consecutive ternary conditionals \u003ccode\u003e?:\u003c/code\u003e;\u003c/li\u003e\n\u003cli\u003e24 binary arithmetic operators of the same precedence in a row;\u003c/li\u003e\n\u003cli\u003e24 relations in a row.\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e12 repetitions of recursive rules, i.e:\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e12 nested function calls;\u003c/li\u003e\n\u003cli\u003e12 selection (\u003ccode\u003e.\u003c/code\u003e) operators in a row;\u003c/li\u003e\n\u003cli\u003e12 indexing (\u003ccode\u003e[_]\u003c/code\u003e) operators in a row;\u003c/li\u003e\n\u003cli\u003e12 nested list, map, or message literals.\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003eThis grammar corresponds to the following operator precedence and associativity:\u003c/p\u003e\n\u003cmarkdown-accessiblity-table\u003e\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003ePrecedence\u003c/th\u003e\n\u003cth\u003eOperator\u003c/th\u003e\n\u003cth\u003eDescription\u003c/th\u003e\n\u003cth\u003eAssociativity\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e1\u003c/td\u003e\n\u003ctd\u003e()\u003c/td\u003e\n\u003ctd\u003eFunction call\u003c/td\u003e\n\u003ctd\u003eLeft-to-right\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e \u003c/td\u003e\n\u003ctd\u003e.\u003c/td\u003e\n\u003ctd\u003eQualified name or field access\u003c/td\u003e\n\u003ctd\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e \u003c/td\u003e\n\u003ctd\u003e[]\u003c/td\u003e\n\u003ctd\u003eIndexing\u003c/td\u003e\n\u003ctd\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e \u003c/td\u003e\n\u003ctd\u003e{}\u003c/td\u003e\n\u003ctd\u003eField initialization\u003c/td\u003e\n\u003ctd\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e2\u003c/td\u003e\n\u003ctd\u003e- (unary)\u003c/td\u003e\n\u003ctd\u003eNegation\u003c/td\u003e\n\u003ctd\u003eRight-to-left\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e \u003c/td\u003e\n\u003ctd\u003e!\u003c/td\u003e\n\u003ctd\u003eLogical NOT\u003c/td\u003e\n\u003ctd\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e3\u003c/td\u003e\n\u003ctd\u003e*\u003c/td\u003e\n\u003ctd\u003eMultiplication\u003c/td\u003e\n\u003ctd\u003eLeft-to-right\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e \u003c/td\u003e\n\u003ctd\u003e/\u003c/td\u003e\n\u003ctd\u003eDivision\u003c/td\u003e\n\u003ctd\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e \u003c/td\u003e\n\u003ctd\u003e%\u003c/td\u003e\n\u003ctd\u003eRemainder\u003c/td\u003e\n\u003ctd\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e4\u003c/td\u003e\n\u003ctd\u003e+\u003c/td\u003e\n\u003ctd\u003eAddition\u003c/td\u003e\n\u003ctd\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e \u003c/td\u003e\n\u003ctd\u003e- (binary)\u003c/td\u003e\n\u003ctd\u003eSubtraction\u003c/td\u003e\n\u003ctd\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e5\u003c/td\u003e\n\u003ctd\u003e== != \u0026lt; \u0026gt; \u0026lt;= \u0026gt;=\u003c/td\u003e\n\u003ctd\u003eRelations\u003c/td\u003e\n\u003ctd\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e \u003c/td\u003e\n\u003ctd\u003ein\u003c/td\u003e\n\u003ctd\u003eInclusion test\u003c/td\u003e\n\u003ctd\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e6\u003c/td\u003e\n\u003ctd\u003e\u0026amp;\u0026amp;\u003c/td\u003e\n\u003ctd\u003eLogical AND\u003c/td\u003e\n\u003ctd\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e7\u003c/td\u003e\n\u003ctd\u003e||\u003c/td\u003e\n\u003ctd\u003eLogical OR\u003c/td\u003e\n\u003ctd\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e8\u003c/td\u003e\n\u003ctd\u003e?:\u003c/td\u003e\n\u003ctd\u003eConditional\u003c/td\u003e\n\u003ctd\u003eRight-to-left\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\u003c/markdown-accessiblity-table\u003e\n\u003cp dir=\"auto\"\u003eThe lexis is defined below. As is typical, the \u003ccode\u003eWHITESPACE\u003c/code\u003e and \u003ccode\u003eCOMMENT\u003c/code\u003e\nproductions are only used to recognize separate lexical elements and are ignored\nby the grammar. Please note, that in the lexer \u003ccode\u003e[]\u003c/code\u003e denotes a character range,\n\u003ccode\u003e*\u003c/code\u003e represents zero or more, \u003ccode\u003e+\u003c/code\u003e represents one or more, and \u003ccode\u003e?\u003c/code\u003e denotes zero\nor one occurrence.\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"IDENT ::= [_a-zA-Z][_a-zA-Z0-9]* - RESERVED\nLITERAL ::= INT_LIT | UINT_LIT | FLOAT_LIT | STRING_LIT | BYTES_LIT\n | BOOL_LIT | NULL_LIT\nINT_LIT ::= -? DIGIT+ | -? 0x HEXDIGIT+\nUINT_LIT ::= INT_LIT [uU]\nFLOAT_LIT ::= -? DIGIT* . DIGIT+ EXPONENT? | -? DIGIT+ EXPONENT\nDIGIT ::= [0-9]\nHEXDIGIT ::= [0-9abcdefABCDEF]\nEXPONENT ::= [eE] [+-]? DIGIT+\nSTRING_LIT ::= [rR]? ( \u0026quot; ~( \u0026quot; | \\r | \\n )* \u0026quot;\n | ' ~( ' | \\r | \\n )* '\n | \u0026quot;\u0026quot;\u0026quot; ~\u0026quot;\u0026quot;\u0026quot;* \u0026quot;\u0026quot;\u0026quot;\n | ''' ~'''* '''\n )\nBYTES_LIT ::= [bB] STRING_LIT\nESCAPE ::= \\ [abfnrtv\\?\u0026quot;'`]\n | \\ [xX] HEXDIGIT HEXDIGIT\n | \\ u HEXDIGIT HEXDIGIT HEXDIGIT HEXDIGIT\n | \\ U HEXDIGIT HEXDIGIT HEXDIGIT HEXDIGIT HEXDIGIT HEXDIGIT HEXDIGIT HEXDIGIT\n | \\ [0-3] [0-7] [0-7]\nBOOL_LIT ::= \u0026quot;true\u0026quot; | \u0026quot;false\u0026quot;\nNULL_LIT ::= \u0026quot;null\u0026quot;\nRESERVED ::= BOOL_LIT | NULL_LIT | \u0026quot;in\u0026quot;\n | \u0026quot;as\u0026quot; | \u0026quot;break\u0026quot; | \u0026quot;const\u0026quot; | \u0026quot;continue\u0026quot; | \u0026quot;else\u0026quot;\n | \u0026quot;for\u0026quot; | \u0026quot;function\u0026quot; | \u0026quot;if\u0026quot; | \u0026quot;import\u0026quot; | \u0026quot;let\u0026quot;\n | \u0026quot;loop\u0026quot; | \u0026quot;package\u0026quot; | \u0026quot;namespace\u0026quot; | \u0026quot;return\u0026quot;\n | \u0026quot;var\u0026quot; | \u0026quot;void\u0026quot; | \u0026quot;while\u0026quot;\nWHITESPACE ::= [\\t\\n\\f\\r ]+\nCOMMENT ::= '//' ~\\n* \\n\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003eIDENT ::= [_a-zA-Z][_a-zA-Z0-9]* - RESERVED\nLITERAL ::= INT_LIT | UINT_LIT | FLOAT_LIT | STRING_LIT | BYTES_LIT\n | BOOL_LIT | NULL_LIT\nINT_LIT ::= -? DIGIT+ | -? 0x HEXDIGIT+\nUINT_LIT ::= INT_LIT [uU]\nFLOAT_LIT ::= -? DIGIT* . DIGIT+ EXPONENT? | -? DIGIT+ EXPONENT\nDIGIT ::= [0-9]\nHEXDIGIT ::= [0-9abcdefABCDEF]\nEXPONENT ::= [eE] [+-]? DIGIT+\nSTRING_LIT ::= [rR]? ( \" ~( \" | \\r | \\n )* \"\n | ' ~( ' | \\r | \\n )* '\n | \"\"\" ~\"\"\"* \"\"\"\n | ''' ~'''* '''\n )\nBYTES_LIT ::= [bB] STRING_LIT\nESCAPE ::= \\ [abfnrtv\\?\"'`]\n | \\ [xX] HEXDIGIT HEXDIGIT\n | \\ u HEXDIGIT HEXDIGIT HEXDIGIT HEXDIGIT\n | \\ U HEXDIGIT HEXDIGIT HEXDIGIT HEXDIGIT HEXDIGIT HEXDIGIT HEXDIGIT HEXDIGIT\n | \\ [0-3] [0-7] [0-7]\nBOOL_LIT ::= \"true\" | \"false\"\nNULL_LIT ::= \"null\"\nRESERVED ::= BOOL_LIT | NULL_LIT | \"in\"\n | \"as\" | \"break\" | \"const\" | \"continue\" | \"else\"\n | \"for\" | \"function\" | \"if\" | \"import\" | \"let\"\n | \"loop\" | \"package\" | \"namespace\" | \"return\"\n | \"var\" | \"void\" | \"while\"\nWHITESPACE ::= [\\t\\n\\f\\r ]+\nCOMMENT ::= '//' ~\\n* \\n\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eFor the sake of a readable representation, the escape\nsequences (\u003ccode\u003eESCAPE\u003c/code\u003e) are kept implicit in string tokens. This means that strings\nwithout the \u003ccode\u003er\u003c/code\u003e or \u003ccode\u003eR\u003c/code\u003e (raw) prefix process \u003ccode\u003eESCAPE\u003c/code\u003e sequences, while in strings\nwith the raw prefix they stay uninterpreted. See documentation of string\nliterals below.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThe following identifiers are reserved due to their use as literal values or in\nthe syntax:\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"false in null true\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003efalse in null true\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThe following identifiers are reserved to allow easier embedding of CEL into a\nhost language.\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"as break const continue else for function if import let loop package\nnamespace return var void while\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003eas break const continue else for function if import let loop package\nnamespace return var void while\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eIn general it is a bad idea for those defining contexts or extensions to use\nidentifiers that are reserved words in programming languages which might embed\nCEL.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eName Resolution\u003c/h3\u003e\u003ca id=\"user-content-name-resolution\" class=\"anchor\" aria-label=\"Permalink: Name Resolution\" href=\"#name-resolution\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eA CEL expression is parsed in the scope of a specific protocol buffer package or\nmessage, which controls the interpretation of names. The scope is set by the\napplication context of an expression. A CEL expression can contain simple names\nas in \u003ccode\u003ea\u003c/code\u003e or qualified names as in \u003ccode\u003ea.b\u003c/code\u003e. The meaning of such expressions is a\ncombination of one or more of:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eVariables and Functions: some simple names refer to variables in the\nexecution context, standard functions, or other name bindings provided by\nthe CEL application.\u003c/li\u003e\n\u003cli\u003eField selection: appending a period and identifier to an expression could\nindicate that we're accessing a field within a protocol buffer or map.\u003c/li\u003e\n\u003cli\u003eProtocol buffer package names: a simple or qualified name could represent an\nabsolute or relative name in the protocol buffer package namespace. Package\nnames must be followed by a message type, or enum constant.\u003c/li\u003e\n\u003cli\u003eProtocol buffer message types and enum constants: following an\noptional protocol buffer package name, a simple or qualified name could\nrefer to a message type or an enum constant in the package's namespace.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003eResolution works as follows. If \u003ccode\u003ea.b\u003c/code\u003e is a name to be resolved in the context of\na protobuf declaration with scope \u003ccode\u003eA.B\u003c/code\u003e, then resolution is attempted, in order,\nas \u003ccode\u003eA.B.a.b\u003c/code\u003e, \u003ccode\u003eA.a.b\u003c/code\u003e, and finally \u003ccode\u003ea.b\u003c/code\u003e. To override this behavior, one can use\n\u003ccode\u003e.a.b\u003c/code\u003e; this name will only be attempted to be resolved in the root scope, i.e.\nas \u003ccode\u003ea.b\u003c/code\u003e.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eIf name qualification is mixed with field selection, the longest prefix of the\nname which resolves in the current lexical scope is used. For example, if\n\u003ccode\u003ea.b.c\u003c/code\u003e resolves to a message declaration, and \u003ccode\u003ea.b\u003c/code\u003e does so as well with \u003ccode\u003ec\u003c/code\u003e a\npossible field selection, then \u003ccode\u003ea.b.c\u003c/code\u003e takes priority over the interpretation\n\u003ccode\u003e(a.b).c\u003c/code\u003e.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eValues\u003c/h2\u003e\u003ca id=\"user-content-values\" class=\"anchor\" aria-label=\"Permalink: Values\" href=\"#values\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eValues in CEL represent any of the following:\u003c/p\u003e\n\u003cmarkdown-accessiblity-table\u003e\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eType\u003c/th\u003e\n\u003cth\u003eDescription\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003eint\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e64-bit signed integers\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003euint\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e64-bit unsigned integers\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003edouble\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e64-bit IEEE floating-point numbers\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003ebool\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eBooleans (\u003ccode\u003etrue\u003c/code\u003e or \u003ccode\u003efalse\u003c/code\u003e)\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003estring\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eStrings of Unicode code points\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003ebytes\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eByte sequences\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003elist\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eLists of values\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003emap\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eAssociative arrays with \u003ccode\u003eint\u003c/code\u003e, \u003ccode\u003euint\u003c/code\u003e, \u003ccode\u003ebool\u003c/code\u003e, or \u003ccode\u003estring\u003c/code\u003e keys\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003enull_type\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eThe value \u003ccode\u003enull\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003emessage names\u003c/td\u003e\n\u003ctd\u003eProtocol buffer messages\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003etype\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eValues representing the types in the first column\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\u003c/markdown-accessiblity-table\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eNumeric Values\u003c/h3\u003e\u003ca id=\"user-content-numeric-values\" class=\"anchor\" aria-label=\"Permalink: Numeric Values\" href=\"#numeric-values\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eCEL supports only 64-bit integers and 64-bit IEEE double-precision\nfloating-point. We only support positive, decimal integer literals; negative\nintegers are produced by the unary negation operator. Note that the integer 7 as\nan \u003ccode\u003eint\u003c/code\u003e is a different value than 7 as a \u003ccode\u003euint\u003c/code\u003e, which would be written \u003ccode\u003e7u\u003c/code\u003e.\nDouble-precision floating-point is also supported, and the integer 7 would be\nwritten \u003ccode\u003e7.0\u003c/code\u003e, \u003ccode\u003e7e0\u003c/code\u003e, \u003ccode\u003e.700e1\u003c/code\u003e, or any equivalent representation using a decimal\npoint or exponent.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eNote that currently there are no automatic arithmetic conversions for the\nnumeric types (\u003ccode\u003eint\u003c/code\u003e, \u003ccode\u003euint\u003c/code\u003e, and \u003ccode\u003edouble\u003c/code\u003e). The arithmetic operators typically\ncontain overloads for arguments of the same numeric type, but not for mixed-type\narguments. Therefore an expression like \u003ccode\u003e1 + 1u\u003c/code\u003e is going to fail to dispatch.\nTo perform mixed-type arithmetic, use explicit conversion functions such as\n\u003ccode\u003euint(1) + 1u\u003c/code\u003e. Such explicit conversions will maintain their meaning even if\narithmetic conversions are added in the future.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eCEL provides no way to control the finer points of floating-point arithmetic,\nsuch as expression evaluation, rounding mode, or exception handling. However,\nany two not-a-number values will compare equal even if their underlying\nproperties are different.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eString and Bytes Values\u003c/h3\u003e\u003ca id=\"user-content-string-and-bytes-values\" class=\"anchor\" aria-label=\"Permalink: String and Bytes Values\" href=\"#string-and-bytes-values\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eStrings are valid sequences of Unicode code points. Bytes are arbitrary\nsequences of octets (eight-bit data).\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eQuoted string literals are delimited by either single- or double-quote\ncharacters, where the closing delimiter must match the opening one, and can\ncontain any unescaped character except the delimiter or newlines (either CR or\nLF).\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eTriple-quoted string literals are delimited by three single-quotes or three\ndouble-quotes, and may contain any unescaped characters except for the delimiter\nsequence. Again, the closing delimiter must match the opening one. Triple-quoted\nstrings may contain newlines.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eBoth sorts of strings can include escape sequences, described below.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eIf preceded by an \u003ccode\u003er\u003c/code\u003e or \u003ccode\u003eR\u003c/code\u003e character, the string is a \u003cem\u003eraw\u003c/em\u003e string and does\nnot interpret escape sequences. Raw strings are useful for expressing strings\nwhich themselves must use escape sequences, such as regular expressions or\nprogram text.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eBytes literals are represented by string literals preceded by a \u003ccode\u003eb\u003c/code\u003e or \u003ccode\u003eB\u003c/code\u003e\ncharacter. The bytes literal is the sequence of bytes given by the UTF-8\nrepresentation of the string literal. In addition, the octal escape sequence are\ninterpreted as octet values rather than as Unicode code points. Both raw and\nmultiline string literals can be used for byte literals.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eEscape sequences are a backslash (\u003ccode\u003e\\\u003c/code\u003e) followed by one of the following:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eA punctuation mark representing itself:\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003e\\\u003c/code\u003e: backslash\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003e?\u003c/code\u003e: question mark\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003e\"\u003c/code\u003e: double quote\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003e'\u003c/code\u003e: single quote\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003e`\u003c/code\u003e: backtick\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eA code for whitespace:\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003ea\u003c/code\u003e: bell\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eb\u003c/code\u003e: backspace\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ef\u003c/code\u003e: form feed\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003en\u003c/code\u003e: line feed\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003er\u003c/code\u003e: carriage return\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003et\u003c/code\u003e: horizontal tab\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ev\u003c/code\u003e: vertical tab\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eA \u003ccode\u003eu\u003c/code\u003e followed by four hexadecimal characters, encoding a Unicode code point\nin the \u003ca href=\"https://www.unicode.org/roadmaps/bmp/\" rel=\"nofollow\"\u003eBMP\u003c/a\u003e.\u003c/li\u003e\n\u003cli\u003eA \u003ccode\u003eU\u003c/code\u003e followed by eight hexadecimal characters, encoding a Unicode code\npoint (in any plane). Valid only for string literals.\u003c/li\u003e\n\u003cli\u003eA \u003ccode\u003ex\u003c/code\u003e or \u003ccode\u003eX\u003c/code\u003e followed by two hexadecimal characters. For strings, it denotes\na Unicode code point. For bytes, it represents an octet value.\u003c/li\u003e\n\u003cli\u003eThree octal digits, in the range \u003ccode\u003e000\u003c/code\u003e to \u003ccode\u003e377\u003c/code\u003e. For strings, it denotes a\nUnicode code point. For bytes, it represents an octet value.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003eAll hexadecimal digits in escape sequences are case-insensitive.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eExamples:\u003c/p\u003e\n\u003cmarkdown-accessiblity-table\u003e\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eCEL Literal\u003c/th\u003e\n\u003cth\u003eMeaning\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003e\"\"\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eEmpty string\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003e'\"\"'\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eString of two double-quote characters\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003e'''x''x'''\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eString of four characters \"\u003ccode\u003ex''x\u003c/code\u003e\"\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003e\"\\\"\"\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eString of one double-quote character\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003e\"\\\\\"\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eString of one backslash character\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003er\"\\\\\"\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eString of two backslash characters\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003eb\"abc\"\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eByte sequence of 97, 98, 99\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003eb\"ÿ\"\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eSequence of bytes 195 and 191 (UTF-8 of ÿ)\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003eb\"\\303\\277\"\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eAlso sequence of bytes 195 and 191\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003e\"\\303\\277\"\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eString of \"ÿ\" (code points 195, 191)\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003e\"\\377\"\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eString of \"ÿ\" (code point 255)\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003eb\"\\377\"\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eSequence of byte 255 (\u003cem\u003enot\u003c/em\u003e UTF-8 of ÿ)\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003e\"\\xFF\"\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eString of \"ÿ\" (code point 255)\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003eb\"\\xff\"\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eSequence of byte 255 (\u003cem\u003enot\u003c/em\u003e UTF-8 of ÿ)\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\u003c/markdown-accessiblity-table\u003e\n\u003cp dir=\"auto\"\u003eThe following constructions are syntactically invalid and will result in a parse\nerror:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eA backslash (\u003ccode\u003e\\\u003c/code\u003e) outside of a valid escape sequence, e.g. \u003ccode\u003e\\s\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eAn invalid Unicode code point, e.g. \u003ccode\u003e\\u2FE0\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eA UTF-16 surrogate code point, even if in a valid UTF-16 surrogate pair,\ne.g. \u003ccode\u003e\\uD83D\\uDE03\u003c/code\u003e or \u003ccode\u003e\\UD83DDE03\u003c/code\u003e.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003eWhile strings must be sequences of valid Unicode code points, no Unicode\nnormalization is attempted on strings, as there are several normal forms, they\ncan be expensive to convert, and we don't know which is desired. If Unicode\nnormalization is desired, it should be performed outside of CEL, or done as a\ncustom extension function.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eLikewise, no advanced collation is attempted on strings, as this depends on the\nnormalization and can be locale-dependent. Strings are simply treated as\nsequences of code points and are ordered with lexicographic ordering based on\nthe numeric value of the code points.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eAggregate Values\u003c/h3\u003e\u003ca id=\"user-content-aggregate-values\" class=\"anchor\" aria-label=\"Permalink: Aggregate Values\" href=\"#aggregate-values\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eLists are ordered sequences of values.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eMaps are a set of key values, and a mapping from these keys to arbitrary values.\nKey values must be an allowed key type: \u003ccode\u003eint\u003c/code\u003e, \u003ccode\u003euint\u003c/code\u003e, \u003ccode\u003ebool\u003c/code\u003e, or \u003ccode\u003estring\u003c/code\u003e. Thus\nmaps are the union of what's allowed in protocol buffer maps and JSON objects.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eNote that the type checker uses a finer-grained notion of list and map types.\nLists are \u003ccode\u003elist(A)\u003c/code\u003e for the homogeneous type \u003ccode\u003eA\u003c/code\u003e of list elements. Maps are\n\u003ccode\u003emap(K, V)\u003c/code\u003e for maps with keys of type \u003ccode\u003eK\u003c/code\u003e and values of type \u003ccode\u003eV\u003c/code\u003e. The type\n\u003ccode\u003edyn\u003c/code\u003e is used for heterogeneous values See\n\u003ca href=\"#gradual-type-checking\"\u003eGradual Type Checking\u003c/a\u003e. But these constraints are only\nenforced within the type checker; at runtime, lists and maps can have\nheterogeneous types.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eAny protocol buffer message is a CEL value, and each message type is its own CEL\ntype, represented as its fully-qualified name.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eA list can be denoted by the expression \u003ccode\u003e[e1, e2, ..., eN]\u003c/code\u003e, a map by \u003ccode\u003e{ek1: ev1, ek2: ev2, ..., ekN: evN}\u003c/code\u003e, and a message by \u003ccode\u003eM{f1: e1, f2: e2, ..., fN: eN}\u003c/code\u003e, where \u003ccode\u003eM\u003c/code\u003e must be a simple or qualified name which resolves to a message\ntype (see \u003ca href=\"#name-resolution\"\u003eName Resolution\u003c/a\u003e). For a map, the entry keys are\nsub-expressions that must evaluate to values of an allowed type (\u003ccode\u003eint\u003c/code\u003e, \u003ccode\u003euint\u003c/code\u003e,\n\u003ccode\u003ebool\u003c/code\u003e, or \u003ccode\u003estring\u003c/code\u003e). For a message, the field names are identifiers. It is an\nerror to have duplicate keys or field names. The empty list, map, and message\nare \u003ccode\u003e[]\u003c/code\u003e, \u003ccode\u003e{}\u003c/code\u003e, and \u003ccode\u003eM{}\u003c/code\u003e, respectively.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eSee \u003ca href=\"#field-selection\"\u003eField Selection\u003c/a\u003e for accessing elements of lists, maps,\nand messages.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eBooleans and Null\u003c/h3\u003e\u003ca id=\"user-content-booleans-and-null\" class=\"anchor\" aria-label=\"Permalink: Booleans and Null\" href=\"#booleans-and-null\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eCEL has \u003ccode\u003etrue\u003c/code\u003e and \u003ccode\u003efalse\u003c/code\u003e as the literals for the \u003ccode\u003ebool\u003c/code\u003e type, with the usual\nmeanings.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThe null value is written \u003ccode\u003enull\u003c/code\u003e. It is used in conversion to and from protocol\nbuffer and JSON data, but otherwise has no built-in meaning in CEL. In\nparticular, null has its own type (\u003ccode\u003enull_type\u003c/code\u003e) and is not necessarily allowed\nwhere a value of some other type is expected.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eType Values\u003c/h3\u003e\u003ca id=\"user-content-type-values\" class=\"anchor\" aria-label=\"Permalink: Type Values\" href=\"#type-values\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eEvery value in CEL has a runtime type which is itself a value. The standard\nfunction \u003ccode\u003etype(x)\u003c/code\u003e returns the type of expression \u003ccode\u003ex\u003c/code\u003e.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eAs types are values, those values (\u003ccode\u003eint\u003c/code\u003e, \u003ccode\u003estring\u003c/code\u003e, etc.) also have a type: the\ntype \u003ccode\u003etype\u003c/code\u003e, which is an expression by itself which in turn also has type\n\u003ccode\u003etype\u003c/code\u003e. So\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003etype(1)\u003c/code\u003e evaluates to \u003ccode\u003eint\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003etype(\"a\")\u003c/code\u003e evaluates to \u003ccode\u003estring\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003etype(1) == string\u003c/code\u003e evaluates to \u003ccode\u003efalse\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003etype(type(1)) == type(string)\u003c/code\u003e evaluates to \u003ccode\u003etrue\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eAbstract Types\u003c/h3\u003e\u003ca id=\"user-content-abstract-types\" class=\"anchor\" aria-label=\"Permalink: Abstract Types\" href=\"#abstract-types\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eA CEL implementation can add new types to the language. These types will be\ngiven names in the same namespace as the other types, but will have no special\nsupport in the language syntax. The only way to construct or use values of these\nabstract types is through functions which the implementor must also provide.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eCommonly, an abstract type will have a representation as a protocol buffer, so\nthat it can be stored or transmitted across a network. In this case, the\nabstract type will be given the same name as the protocol buffer, which will\nprevent CEL programs from being able to use that particular protocol buffer\nmessage type; they will not be able to construct values of that type by message\nexpressions nor access the message fields. The abstract type remains abstract.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eBy default, CEL uses \u003ccode\u003egoogle.protobuf.Timestamp\u003c/code\u003e and \u003ccode\u003egoogle.protobuf.Duration\u003c/code\u003e\nas abstract types. The standard functions provide ways to construct and\nmanipulate these values, but CEL programs cannot construct them with message\nexpressions or access their message fields.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eProtocol Buffer Data Conversion\u003c/h3\u003e\u003ca id=\"user-content-protocol-buffer-data-conversion\" class=\"anchor\" aria-label=\"Permalink: Protocol Buffer Data Conversion\" href=\"#protocol-buffer-data-conversion\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eProtocol buffers have a richer range of types than CEL, so Protocol buffer data\nis converted to CEL data when read from a message field, and CEL data is\nconverted in the other direction when initializing a field. In general, protocol\nbuffer data can be converted to CEL without error, but range errors are possible\nin the other direction.\u003c/p\u003e\n\u003cmarkdown-accessiblity-table\u003e\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eProtocol Buffer Field Type\u003c/th\u003e\n\u003cth\u003eCEL Type\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003eint32, int64, sint32, sint64, sfixed32, sfixed64\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003eint\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003euint32, uint64, fixed32, fixed64\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003euint\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003efloat, double\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003edouble\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ebool, string, bytes\u003c/td\u003e\n\u003ctd\u003esame\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eenum E\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003eint\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003erepeated\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003elist\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003emap\u0026lt;K, V\u0026gt;\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003emap\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eoneof\u003c/td\u003e\n\u003ctd\u003eoptions expanded individually, at most one is set\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003emessage M\u003c/td\u003e\n\u003ctd\u003eM, except for conversions below\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\u003c/markdown-accessiblity-table\u003e\n\u003cp dir=\"auto\"\u003eSigned integers, unsigned integers, and floating point numbers are converted to\nthe singular CEL type of the same sort. The CEL type is capable of expressing\nthe full range of protocol buffer values. When converting from CEL to protocol\nbuffers, an out-of-range CEL value results in an error.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eBoolean, string, and bytes types have identical ranges and are converted without\nerror.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eProtocol buffer enum values are converted to the corresponding \u003ccode\u003eint\u003c/code\u003e value.\nProtocol buffer enum fields can accept any signed 32-bit number, values outside\nthat range will raise an error.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eRepeated fields are converted to CEL lists of converted values, preserving the\norder. In the other direction, the CEL list elements must be of the right type\nand value to be converted to the corresponding protocol buffer type. Similarly,\nprotocol buffer maps are converted to CEL maps, and CEL map keys and values must\nhave the right type and value to be converted in the other direction.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eOneof fields are represented by the translation of each of their options as a\nseparate field, but at most one of these fields will be \"set\", as detected by\nthe \u003ccode\u003ehas()\u003c/code\u003e macro. See \u003ca href=\"#macros\"\u003eMacros\u003c/a\u003e.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eSince protocol buffer messages are first-class CEL values, message-valued fields\nare used without conversion.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eEvery protocol buffer field has a default value, and there is no semantic\ndifference between a field set to this default value, and an unset field. For\nmessage fields, their default value is just the unset state, and an unset\nmessage field is distinct from one set to an empty (i.e. all-unset) message.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThe \u003ccode\u003ehas()\u003c/code\u003e macro (see \u003ca href=\"#macros\"\u003eMacros\u003c/a\u003e) tells whether a message field is set\n(i.e. not unset, hence not set to the default value). If an unset field is\nnevertheless selected, it evaluates to its default value, or if it is a message\nfield, it evaluates to an empty (i.e. all-unset) message. This allows\nexpressions to use iterative field selection to examine the state of fields in\ndeeply nested messages without needing to test whether every intermediate field\nis set. (See exception for wrapper types, below.)\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eDynamic Values\u003c/h3\u003e\u003ca id=\"user-content-dynamic-values\" class=\"anchor\" aria-label=\"Permalink: Dynamic Values\" href=\"#dynamic-values\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eCEL automatically converts certain protocol buffer messages in the\n\u003ccode\u003egoogle.protobuf\u003c/code\u003e package to other types.\u003c/p\u003e\n\u003cmarkdown-accessiblity-table\u003e\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003egoogle.protobuf message\u003c/th\u003e\n\u003cth\u003eCEL Conversion\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003eAny\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003edynamically converted to the contained message type, or error\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003eListValue\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003elist of \u003ccode\u003eValue\u003c/code\u003e messages\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003eStruct\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003emap (with string keys, \u003ccode\u003eValue\u003c/code\u003e values)\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003eValue\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003edynamically converted to the contained type (null, double, string, bool, \u003ccode\u003eStruct\u003c/code\u003e, or \u003ccode\u003eListValue\u003c/code\u003e)\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ewrapper types\u003c/td\u003e\n\u003ctd\u003econverted as eponymous field type\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\u003c/markdown-accessiblity-table\u003e\n\u003cp dir=\"auto\"\u003eThe wrapper types are \u003ccode\u003eBoolValue\u003c/code\u003e, \u003ccode\u003eBytesValue\u003c/code\u003e, \u003ccode\u003eDoubleValue\u003c/code\u003e, \u003ccode\u003eFloatValue\u003c/code\u003e,\n\u003ccode\u003eInt32Value\u003c/code\u003e, \u003ccode\u003eInt64Value\u003c/code\u003e, \u003ccode\u003eNullValue\u003c/code\u003e, \u003ccode\u003eStringValue\u003c/code\u003e, \u003ccode\u003eUint32Value\u003c/code\u003e, and\n\u003ccode\u003eUint64Value\u003c/code\u003e. Values of these wrapper types are converted to the obvious type.\nAdditionally, field selection of an unset message field of wrapper type will\nevaluate to \u003ccode\u003enull\u003c/code\u003e, instead of the default message. This is an exception to the\nusual evaluation of unset message fields.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eNote that this implies some cascading conversions. An \u003ccode\u003eAny\u003c/code\u003e message might be\nconverted to a \u003ccode\u003eStruct\u003c/code\u003e, one of whose \u003ccode\u003eValue\u003c/code\u003e-typed values might be converted to\na \u003ccode\u003eListValue\u003c/code\u003e of more values, and so on.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eAlso, note that all of these conversions are dynamic at runtime, so CEL's static\ntype analysis cannot avoid the possibility of type-related errors in expressions\nusing these dynamic values.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eJSON Data Conversion\u003c/h2\u003e\u003ca id=\"user-content-json-data-conversion\" class=\"anchor\" aria-label=\"Permalink: JSON Data Conversion\" href=\"#json-data-conversion\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eCEL can also work with JSON data. Since there is a natural correspondence of\nmost CEL data with protocol buffer data, and protocol buffers have a\n\u003ca href=\"https://developers.google.com/protocol-buffers/docs/proto3#json\" rel=\"nofollow\"\u003edefined mapping\u003c/a\u003e\nto JSON, this creates a natural mapping of CEL to JSON. This creates an exact\nbidirectional mapping between JSON types and a subset of CEL data:\u003c/p\u003e\n\u003cmarkdown-accessiblity-table\u003e\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eJSON Type\u003c/th\u003e\n\u003cth\u003eCEL Type\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003enull\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003enull\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eBoolean\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003ebool\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eNumber\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003edouble\u003c/code\u003e (except infinities or NaN)\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eString\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003estring\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eArray\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003elist\u003c/code\u003e of bi-convertible elements\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eObject\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003emap\u003c/code\u003e (with string keys, bi-convertible values)\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\u003c/markdown-accessiblity-table\u003e\n\u003cp dir=\"auto\"\u003eWe define JSON mappings for much of the remainder of CEL data, but note that\nthis data will not map back in to CEL as the same value:\u003c/p\u003e\n\u003cmarkdown-accessiblity-table\u003e\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eCEL Data\u003c/th\u003e\n\u003cth\u003eJSON Data\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003eint\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eNumber if in interoperable range, otherwise decimal String.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003euint\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eNumber if in interoperable range, otherwise decimal String.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003edouble infinity\u003c/td\u003e\n\u003ctd\u003eString \u003ccode\u003e\"Infinity\"\u003c/code\u003e or \u003ccode\u003e\"-Infinity\"\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003edouble NaN\u003c/td\u003e\n\u003ctd\u003eString \"NaN\"\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003ebytes\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eString of base64-encoded bytes\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003emessage\u003c/td\u003e\n\u003ctd\u003eJSON conversion of protobuf message.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003elist\u003c/code\u003e of convertible elements\u003c/td\u003e\n\u003ctd\u003eJSON Array of converted values\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003elist\u003c/code\u003e with a non-convertible element\u003c/td\u003e\n\u003ctd\u003enone\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003emap\u003c/code\u003e with string keys and convertible values\u003c/td\u003e\n\u003ctd\u003eJSON Object with converted values\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003emap\u003c/code\u003e with a non-string key or a non-convertible value\u003c/td\u003e\n\u003ctd\u003enone\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003etype\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003enone\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\u003c/markdown-accessiblity-table\u003e\n\u003cp dir=\"auto\"\u003eThe \"interoperable\" range of integer values is \u003ccode\u003e-(2^53-1)\u003c/code\u003e to \u003ccode\u003e2^53 - 1\u003c/code\u003e.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eGradual Type Checking\u003c/h2\u003e\u003ca id=\"user-content-gradual-type-checking\" class=\"anchor\" aria-label=\"Permalink: Gradual Type Checking\" href=\"#gradual-type-checking\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eCEL is a dynamically-typed language, meaning that the types of the values of the\nvariables and expressions might not be known until runtime. However, CEL has an\noptional type-checking phase that takes the types declared for all functions and\nvariables and tries to deduce the type of the expression and of all its\nsub-expressions. This is not always possible, due to the dynamic expansion of\ncertain messages like \u003ccode\u003eStruct\u003c/code\u003e, \u003ccode\u003eValue\u003c/code\u003e, and \u003ccode\u003eAny\u003c/code\u003e (see\n\u003ca href=\"#dynamic-values\"\u003eDynamic Values\u003c/a\u003e). However, if a CEL program does not use\ndynamically-expanded messages, it can be statically type-checked.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThe type checker uses a richer type system than the types of the dynamic values:\nlists have a type parameter for the type of the elements, and maps have two\nparameters for the types of keys and values, respectively. These richer types\npreserve the stronger type guarantees that protocol buffer messages have. We can\ninfer stronger types from the standard functions, such as accessing list\nelements or map fields. However, the \u003ccode\u003etype()\u003c/code\u003e function and dynamic dispatch to\nparticular function overloads only use the coarser types of the dynamic values.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThe type checker also introduces the \u003ccode\u003edyn\u003c/code\u003e type, which is the union of all other\ntypes. Therefore the type checker could accept a list of heterogeneous values as\n\u003ccode\u003edyn([1, 3.14, \"foo\"])\u003c/code\u003e, which is given the type \u003ccode\u003elist(dyn)\u003c/code\u003e. The standard\nfunction \u003ccode\u003edyn\u003c/code\u003e has no effect at runtime, but signals to the type checker that\nits argument should be considered of type \u003ccode\u003edyn\u003c/code\u003e, \u003ccode\u003elist(dyn)\u003c/code\u003e, or a \u003ccode\u003edyn\u003c/code\u003e-valued\nmap.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eA CEL type checker attempts to identify possible runtime errors (see\n\u003ca href=\"#runtime-errors\"\u003eRuntime Errors\u003c/a\u003e), particularly \u003ccode\u003eno_matching_overload\u003c/code\u003e and\n\u003ccode\u003eno_such_field\u003c/code\u003e, ahead of runtime. It also serves to optimize execution speed\nby narrowing down the number of possible matching overloads for a function\ncall, and by allowing for a more efficient (unboxed) runtime representation of\nvalues.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eBy construction, a CEL expression that does not use the dynamic features coming\nfrom \u003ccode\u003eStruct\u003c/code\u003e, \u003ccode\u003eValue\u003c/code\u003e, or \u003ccode\u003eAny\u003c/code\u003e, can be fully statically type-checked and all\noverloads can be resolved ahead of runtime.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eIf a CEL expression uses a mixture of dynamic and static features, a type\nchecker will still attempt to derive as much information as possible and\ndelegate undecidable type decisions to runtime.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThe type checker is an optional phase of evaluation. Running the type checker\ndoes not affect the result of evaluation, it can only reject expressions as\nill-typed in a given typing context.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eEvaluation\u003c/h2\u003e\u003ca id=\"user-content-evaluation\" class=\"anchor\" aria-label=\"Permalink: Evaluation\" href=\"#evaluation\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eFor a given evaluation environment, a CEL expression will deterministically\nevaluate to either a value or an error. Here are how different expressions are\nevaluated:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003cstrong\u003eLiterals:\u003c/strong\u003e the various kinds of literals (numbers, booleans, strings,\nbytes, and \u003ccode\u003enull\u003c/code\u003e) evaluate to the values they represent.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eVariables:\u003c/strong\u003e variables are looked up in the binding environment. An\nunbound variable evaluates to an error.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eList, Map, and Message expressions:\u003c/strong\u003e each sub-expression is evaluated and\nif any sub-expression results in an error, this expression results in an\nerror. Otherwise, it results in the list, map, or message of the\nsub-expression results, or an error if one of the values is of the wrong\ntype.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eField selection:\u003c/strong\u003e see \u003ca href=\"#field-selection\"\u003eField Selection\u003c/a\u003e.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eMacros:\u003c/strong\u003e see \u003ca href=\"#macros\"\u003eMacros\u003c/a\u003e.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eLogical operators:\u003c/strong\u003e see \u003ca href=\"#logical-operators\"\u003eLogical Operators\u003c/a\u003e.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eOther operators:\u003c/strong\u003e operators are translated into specially-named functions\nand the sub-expressions become their arguments, for instance \u003ccode\u003ee1 + e2\u003c/code\u003e\nbecomes \u003ccode\u003e_+_(e1, e2)\u003c/code\u003e, which is then evaluated as a normal function.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eNormal functions:\u003c/strong\u003e all argument sub-expressions are evaluated and if any\nresults in an error, then this expression results in an error. Otherwise,\nthe function is identified by its name and dispatched to a particular\noverload based on the types of the sub-expression values. See\n\u003ca href=\"#functions\"\u003eFunctions\u003c/a\u003e.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003eBecause CEL is free of side effects, the order of evaluation among\nsub-expressions is not guaranteed. If multiple sub-expressions would evaluate to\nerrors causing the enclosing expression to evaluate to an error, it will\npropagate one or more of the sub-expression errors, but it is not specified\nwhich ones.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eEvaluation Environment\u003c/h3\u003e\u003ca id=\"user-content-evaluation-environment\" class=\"anchor\" aria-label=\"Permalink: Evaluation Environment\" href=\"#evaluation-environment\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eA CEL expression is parsed and evaluated in the scope of a particular protocol\nbuffer package, which controls name resolution as described above, and a binding\ncontext, which binds identifiers to values, errors, and functions. A given\nidentifier has different meanings as a function name or as a variable, depending\non the use. For instance in the expression \u003ccode\u003esize(requests) \u0026gt; size\u003c/code\u003e, the first\n\u003ccode\u003esize\u003c/code\u003e is a function, and the second is a variable.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThe CEL implementation provides mechanisms for adding bindings of variable names\nto either values or errors. The implementation will also provide function\nbindings for at least all the standard functions listed below.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eWhere feasible, CEL implementations ensure that a value bound to a variable name\nor returned by a custom function conforms to the CEL type declared for that\nvalue or, for dynamic typed values, \u003cem\u003ea\u003c/em\u003e CEL type. Where implementations allow\nnonconforming values, (e.g. strings with invalid Unicode code points) to be\nprovided to a CEL program, conformance must be enforced by the application\nembedding the CEL program in order to ensure type safety is maintained.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eSome implementations might make use of a \u003cem\u003econtext proto\u003c/em\u003e, where a single\nprotocol buffer message represents all variable bindings: each field in the\nmessage is a binding of the field name to the field value. This provides a\nconvenient encapsulation of the binding environment.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThe evaluation environment can also specify the expected type of the result. If\nthe expected type is one of the protocol buffer wrapper messages, then CEL will\nattempt to convert the result to the wrapper message, or will raise an error if\nthe conversion fails.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eRuntime Errors\u003c/h3\u003e\u003ca id=\"user-content-runtime-errors\" class=\"anchor\" aria-label=\"Permalink: Runtime Errors\" href=\"#runtime-errors\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eIn general, when a runtime error is produced, expression evaluation is\nterminated; exceptions to this rule are discussed in\n\u003ca href=\"#logical-operators\"\u003eLogical Operators\u003c/a\u003e and \u003ca href=\"#macros\"\u003eMacros\u003c/a\u003e.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eCEL provides the following built-in runtime errors:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003eno_matching_overload\u003c/code\u003e: this function has no overload for the types of the\narguments.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eno_such_field\u003c/code\u003e: a map or message does not contain the desired field.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003eThere is no in-language representation of errors, no generic way to raise them,\nand no way to catch or bypass errors, except for the short-circuiting behavior\nof the logical operators, and macros.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eLogical Operators\u003c/h3\u003e\u003ca id=\"user-content-logical-operators\" class=\"anchor\" aria-label=\"Permalink: Logical Operators\" href=\"#logical-operators\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eIn the conditional operator \u003ccode\u003ee ? e1 : e2\u003c/code\u003e, evaluates to \u003ccode\u003ee1\u003c/code\u003e if \u003ccode\u003ee\u003c/code\u003e evaluates to\n\u003ccode\u003etrue\u003c/code\u003e, and \u003ccode\u003ee2\u003c/code\u003e if \u003ccode\u003ee\u003c/code\u003e evaluates to \u003ccode\u003efalse\u003c/code\u003e. The untaken branch is presumed to\nnot be executed, though that is an implementation detail.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eIn the boolean operators \u003ccode\u003e\u0026amp;\u0026amp;\u003c/code\u003e and \u003ccode\u003e||\u003c/code\u003e: if any of their operands uniquely\ndetermines the result (\u003ccode\u003efalse\u003c/code\u003e for \u003ccode\u003e\u0026amp;\u0026amp;\u003c/code\u003e and \u003ccode\u003etrue\u003c/code\u003e for \u003ccode\u003e||\u003c/code\u003e) the other operand\nmay or may not be evaluated, and if that evaluation produces a runtime error, it\nwill be ignored. This makes those operators commutative (in contrast to\ntraditional boolean short-circuit operators). The rationale for this behavior is\nto allow the boolean operators to be mapped to indexed queries, and align better\nwith SQL semantics.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eTo get traditional left-to-right short-circuiting evaluation of logical\noperators, as in C or other languages (also called \"McCarthy Evaluation\"), the\nexpression \u003ccode\u003ee1 \u0026amp;\u0026amp; e2\u003c/code\u003e can be rewritten \u003ccode\u003ee1 ? e2 : false\u003c/code\u003e. Similarly, \u003ccode\u003ee1 || e2\u003c/code\u003e\ncan be rewritten \u003ccode\u003ee1 ? true : e2\u003c/code\u003e.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eMacros\u003c/h3\u003e\u003ca id=\"user-content-macros\" class=\"anchor\" aria-label=\"Permalink: Macros\" href=\"#macros\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eCEL supports a small set of predefined macros. Macro invocations have the same\nsyntax as function calls, but follow different type checking rules and runtime\nsemantics than regular functions. An application of CEL opts-in to which macros\nto support, selecting from the predefined set of macros. The currently available\nmacros are:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003ehas(e.f)\u003c/code\u003e: tests whether a field is available. See \"Field Selection\" below.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ee.all(x, p)\u003c/code\u003e: tests whether a predicate holds for all elements of a list\n\u003ccode\u003ee\u003c/code\u003e or keys of a map \u003ccode\u003ee\u003c/code\u003e. Here \u003ccode\u003ex\u003c/code\u003e is a simple identifier to be used in \u003ccode\u003ep\u003c/code\u003e\nwhich binds to the element or key. The \u003ccode\u003eall()\u003c/code\u003e macro combines per-element\npredicate results with the \"and\" (\u003ccode\u003e\u0026amp;\u0026amp;\u003c/code\u003e) operator, so if any predicate\nevaluates to \u003ccode\u003efalse\u003c/code\u003e, the macro evaluates to \u003ccode\u003efalse\u003c/code\u003e, ignoring any errors\nfrom other predicates.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ee.exists(x, p)\u003c/code\u003e: like the \u003ccode\u003eall()\u003c/code\u003e macro, but combines the predicate results\nwith the \"or\" (\u003ccode\u003e||\u003c/code\u003e) operator, so if any predicate evaluates to \u003ccode\u003etrue\u003c/code\u003e, the\nmacro evaluates to \u003ccode\u003etrue\u003c/code\u003e, ignoring any errors from other predicates.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ee.exists_one(x, p)\u003c/code\u003e: like the \u003ccode\u003eexists()\u003c/code\u003e macro, but evaluates to \u003ccode\u003etrue\u003c/code\u003e only\nif the predicate of exactly one element/key evaluates to \u003ccode\u003etrue\u003c/code\u003e, and the\nrest to \u003ccode\u003efalse\u003c/code\u003e. Any other combination of boolean results evaluates to\n\u003ccode\u003efalse\u003c/code\u003e, and any predicate error causes the macro to raise an error.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ee.map(x, t)\u003c/code\u003e:\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003etransforms a list \u003ccode\u003ee\u003c/code\u003e by taking each element \u003ccode\u003ex\u003c/code\u003e to the\nfunction given by the expression \u003ccode\u003et\u003c/code\u003e, which can use the variable \u003ccode\u003ex\u003c/code\u003e. For\ninstance, \u003ccode\u003e[1, 2, 3].map(n, n * n)\u003c/code\u003e evaluates to \u003ccode\u003e[1, 4, 9]\u003c/code\u003e. Any evaluation\nerror for any element causes the macro to raise an error.\u003c/li\u003e\n\u003cli\u003etransforms a map \u003ccode\u003ee\u003c/code\u003e by taking each key in the map \u003ccode\u003ex\u003c/code\u003e to the function\ngiven by the expression \u003ccode\u003et\u003c/code\u003e, which can use the variable \u003ccode\u003ex\u003c/code\u003e. For\ninstance, \u003ccode\u003e{'one': 1, 'two': 2}.map(k, k)\u003c/code\u003e evaluates to \u003ccode\u003e['one', 'two']\u003c/code\u003e.\nAny evaluation error for any element causes the macro to raise an error.\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ee.map(x, p, t)\u003c/code\u003e: Same as the two-arg map but with a conditional \u003ccode\u003ep\u003c/code\u003e filter\nbefore the value is transformed.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ee.filter(x, p)\u003c/code\u003e:\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003efor a list \u003ccode\u003ee\u003c/code\u003e, returns the sublist of all elements \u003ccode\u003ex\u003c/code\u003e which\nevaluate to \u003ccode\u003etrue\u003c/code\u003e in the predicate expression \u003ccode\u003ep\u003c/code\u003e (which can use variable\n\u003ccode\u003ex\u003c/code\u003e). For instance, \u003ccode\u003e[1, 2, 3].filter(i, i % 2 \u0026gt; 0)\u003c/code\u003e evaluates to \u003ccode\u003e[1, 3]\u003c/code\u003e.\nIf no elements evaluate to \u003ccode\u003etrue\u003c/code\u003e, the result is an empty list. Any\nevaluation error for any element causes the macro to raise an error.\u003c/li\u003e\n\u003cli\u003efor a map \u003ccode\u003ee\u003c/code\u003e, returns the list of all map keys \u003ccode\u003ex\u003c/code\u003e which\nevaluate to \u003ccode\u003etrue\u003c/code\u003e in the predicate expression \u003ccode\u003ep\u003c/code\u003e (which can use variable\n\u003ccode\u003ex\u003c/code\u003e). For instance, \u003ccode\u003e{'one': 1, 'two': 2}.filter(k, k == 'one')\u003c/code\u003e evaluates\nto \u003ccode\u003e['one']\u003c/code\u003e. If no elements evaluate to \u003ccode\u003etrue\u003c/code\u003e, the result is an empty\nlist. Any evaluation error for any element causes the macro to raise an error.\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eField Selection\u003c/h3\u003e\u003ca id=\"user-content-field-selection\" class=\"anchor\" aria-label=\"Permalink: Field Selection\" href=\"#field-selection\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eA field selection expression, \u003ccode\u003ee.f\u003c/code\u003e, can be applied both to messages and to\nmaps. For maps, selection is interpreted as the field being a string key.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThe semantics depends on the type of the result of evaluating expression \u003ccode\u003ee\u003c/code\u003e:\u003c/p\u003e\n\u003col dir=\"auto\"\u003e\n\u003cli\u003eIf \u003ccode\u003ee\u003c/code\u003e evaluates to a message and \u003ccode\u003ef\u003c/code\u003e is not declared in this message, the runtime\nerror \u003ccode\u003eno_such_field\u003c/code\u003e is raised.\u003c/li\u003e\n\u003cli\u003eIf \u003ccode\u003ee\u003c/code\u003e evaluates to a message and \u003ccode\u003ef\u003c/code\u003e is declared, but the field is not set, the\ndefault value of the field's type will be produced. Note that this is \u003ccode\u003enull\u003c/code\u003e\nfor messages or the according primitive default value as determined by\nproto2 or proto3 semantics.\u003c/li\u003e\n\u003cli\u003eIf \u003ccode\u003ee\u003c/code\u003e evaluates to a map, then \u003ccode\u003ee.f\u003c/code\u003e is equivalent to \u003ccode\u003ee['f']\u003c/code\u003e (where \u003ccode\u003ef\u003c/code\u003e\nis still being used as a meta-variable, e.g. the expression \u003ccode\u003ex.foo\u003c/code\u003e is\nequivalent to the expression \u003ccode\u003ex['foo']\u003c/code\u003e when \u003ccode\u003ex\u003c/code\u003e evaluates to a map).\u003c/li\u003e\n\u003cli\u003eIn all other cases, \u003ccode\u003ee.f\u003c/code\u003e evaluates to an error.\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp dir=\"auto\"\u003eTo test for the presence of a field, the boolean-valued macro \u003ccode\u003ehas(e.f)\u003c/code\u003e can be\nused.\u003c/p\u003e\n\u003col dir=\"auto\"\u003e\n\u003cli\u003eIf \u003ccode\u003ee\u003c/code\u003e evaluates to a map, then \u003ccode\u003ehas(e.f)\u003c/code\u003e indicates whether the string \u003ccode\u003ef\u003c/code\u003e\nis a key in the map (note that \u003ccode\u003ef\u003c/code\u003e must syntactically be an identifier).\u003c/li\u003e\n\u003cli\u003eIf \u003ccode\u003ee\u003c/code\u003e evaluates to a message and \u003ccode\u003ef\u003c/code\u003e is not a declared field for the\nmessage, \u003ccode\u003ehas(e.f)\u003c/code\u003e raises a \u003ccode\u003eno_such_field\u003c/code\u003e error.\u003c/li\u003e\n\u003cli\u003eIf \u003ccode\u003ee\u003c/code\u003e evaluates to a protocol buffers version 2 message and \u003ccode\u003ef\u003c/code\u003e is a\ndefined field:\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eIf \u003ccode\u003ef\u003c/code\u003e is a repeated field or map field, \u003ccode\u003ehas(e.f)\u003c/code\u003e indicates whether\nthe field is non-empty.\u003c/li\u003e\n\u003cli\u003eIf \u003ccode\u003ef\u003c/code\u003e is a singular or oneof field, \u003ccode\u003ehas(e.f)\u003c/code\u003e indicates\nwhether the field is set.\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eIf \u003ccode\u003ee\u003c/code\u003e evaluates to a protocol buffers version 3 message and \u003ccode\u003ef\u003c/code\u003e is a\ndefined field:\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eIf \u003ccode\u003ef\u003c/code\u003e is a repeated field or map field, \u003ccode\u003ehas(e.f)\u003c/code\u003e indicates whether\nthe field is non-empty.\u003c/li\u003e\n\u003cli\u003eIf \u003ccode\u003ef\u003c/code\u003e is a oneof or singular message field, \u003ccode\u003ehas(e.f)\u003c/code\u003e indicates\nwhether the field is set.\u003c/li\u003e\n\u003cli\u003eIf \u003ccode\u003ef\u003c/code\u003e is some other singular field, \u003ccode\u003ehas(e.f)\u003c/code\u003e indicates whether the\nfield's value is its default value (zero for numeric fields, \u003ccode\u003efalse\u003c/code\u003e for\nbooleans, empty for strings and bytes).\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eIn all other cases, \u003ccode\u003ehas(e.f)\u003c/code\u003e evaluates to an error.\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003ePerformance\u003c/h2\u003e\u003ca id=\"user-content-performance\" class=\"anchor\" aria-label=\"Permalink: Performance\" href=\"#performance\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eSince one of the main applications for CEL is for execution of untrusted\nexpressions with reliable containment, the time and space cost of evaluation\nis an essential part of the specification of the language. But we also want to\ngive considerable freedom in how to implement the language. To balance these\nconcerns, we specify only the time and space computational complexity of\nlanguage constructs and standard functions (see \u003ca href=\"#functions\"\u003eFunctions\u003c/a\u003e).\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eCEL applications are responsible for noting the computational complexity of\nany extension functions they provide.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eAbstract Sizes\u003c/h3\u003e\u003ca id=\"user-content-abstract-sizes\" class=\"anchor\" aria-label=\"Permalink: Abstract Sizes\" href=\"#abstract-sizes\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eSpace and time complexity will be measured in terms of an abstract size\nmeasurement of CEL expressions and values. The size of a CEL value depends on\nits type:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003cem\u003estring\u003c/em\u003e: The size is its length, i.e. the number of code points, plus a\nconstant.\u003c/li\u003e\n\u003cli\u003e\u003cem\u003ebytes\u003c/em\u003e: The size is its length, i.e. the number of bytes, plus a constant.\u003c/li\u003e\n\u003cli\u003e\u003cem\u003elist\u003c/em\u003e: The size is the sum of sizes of its entries, plus a constant.\u003c/li\u003e\n\u003cli\u003e\u003cem\u003emap\u003c/em\u003e: The size is the sum of the key size plus the value size for all of\nits entries, plus a constant.\u003c/li\u003e\n\u003cli\u003e\u003cem\u003emessage\u003c/em\u003e: The size is the sum of the size of all fields, plus a constant.\u003c/li\u003e\n\u003cli\u003eAll other values have constant size.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003eThe size of a CEL program is:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003cem\u003estring literal\u003c/em\u003e: The size of the resulting value.\u003c/li\u003e\n\u003cli\u003e\u003cem\u003ebytes literal\u003c/em\u003e: The size of the resulting value.\u003c/li\u003e\n\u003cli\u003eGrammatical aggregates are the sum of the size of their components.\u003c/li\u003e\n\u003cli\u003eGrammatical primitives other than above have constant size.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003eThus, the size of a CEL program is bounded by either the length of the source\ntext string or the bytes of the proto-encoded AST.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThe inputs to a CEL expression are the \u003cem\u003ebindings\u003c/em\u003e given to the evaluator and\nthe \u003cem\u003eliterals\u003c/em\u003e within the expression itself.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eTime Complexity\u003c/h3\u003e\u003ca id=\"user-content-time-complexity\" class=\"anchor\" aria-label=\"Permalink: Time Complexity\" href=\"#time-complexity\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eUnless otherwise noted, the time complexity of an expression is the sum of the\ntime complexity of its sub-expressions, plus the sum of the sizes of the\nsub-expression values, plus a constant.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eFor instance, an expression \u003ccode\u003ex\u003c/code\u003e has constant time complexity since it has no\nsub-expressions. An expression \u003ccode\u003ex != y\u003c/code\u003e takes time proportional to the sum of\nsizes of the bindings of \u003ccode\u003ex\u003c/code\u003e and \u003ccode\u003ey\u003c/code\u003e, plus a constant.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eSome functions cost less than this:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eThe conditional expression \u003ccode\u003e_?_:_\u003c/code\u003e, only evaluates one of the alternative\nsub-expressions.\u003c/li\u003e\n\u003cli\u003eFor the \u003ccode\u003esize()\u003c/code\u003e function on lists and maps, the time is proportional to\nthe length of its input, not its total size (plus the time of the\nsub-expression).\u003c/li\u003e\n\u003cli\u003eThe index operator on lists takes constant time (plus the time of the\nsub-expressions).\u003c/li\u003e\n\u003cli\u003eThe select operator on messages takes constant time (plus the time of the\nsub-expression).\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003eSome functions take more time than this. The following functions take time\nproportional to the \u003cem\u003eproduct\u003c/em\u003e of their input sizes (plus the time of the\nsub-expressions):\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eThe index operator on maps.\u003c/li\u003e\n\u003cli\u003eThe select operator on maps.\u003c/li\u003e\n\u003cli\u003eThe in operator.\u003c/li\u003e\n\u003cli\u003eThe \u003ccode\u003econtains\u003c/code\u003e, \u003ccode\u003estartsWith\u003c/code\u003e, \u003ccode\u003eendsWith\u003c/code\u003e, and \u003ccode\u003ematches\u003c/code\u003e functions on\nstrings.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003eSee below for the time cost of macros.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eImplementations are free to provide a more performant implementation. For\ninstance, a hashing implementation of maps would make indexing/selection\nfaster, but we do not require such sophistication from all implementations.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eSpace Complexity\u003c/h3\u003e\u003ca id=\"user-content-space-complexity\" class=\"anchor\" aria-label=\"Permalink: Space Complexity\" href=\"#space-complexity\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eUnless otherwise noted, the space complexity of an expression is the sum of the\nspace complexity of its sub-expressions, plus a constant. The exceptions are:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003cem\u003eLiterals\u003c/em\u003e: Message, map, and list literals allocate new space for their\noutput.\u003c/li\u003e\n\u003cli\u003e\u003cem\u003eConcatenation\u003c/em\u003e: The \u003ccode\u003e_+_\u003c/code\u003e operator on lists and strings allocate new space\nfor their output.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003eSee below for the space cost of macros.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eWe'll assume that bytes-to-string and string-to-bytes conversions do not need\nto allocate new space.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eMacro Performance\u003c/h3\u003e\u003ca id=\"user-content-macro-performance\" class=\"anchor\" aria-label=\"Permalink: Macro Performance\" href=\"#macro-performance\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eMacros can take considerably more time and space than other constructs, and\ncan lead to exponential behavior when nested or chained. For instance,\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"[0,1].all(x,\n [0,1].all(x,\n ...\n [0,1].all(x, 1/0)...))\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003e[0,1].all(x,\n [0,1].all(x,\n ...\n [0,1].all(x, 1/0)...))\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003etakes exponential (in the size of the expression) time to evaluate, while\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"[\u0026quot;foo\u0026quot;,\u0026quot;bar\u0026quot;].map(x, [x+x,x+x]).map(x, [x+x,x+x])...map(x, [x+x,x+x])\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003e[\"foo\",\"bar\"].map(x, [x+x,x+x]).map(x, [x+x,x+x])...map(x, [x+x,x+x])\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eis exponential in both time and space.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThe time and space cost of macros is the cost of the range sub-expression \u003ccode\u003ee\u003c/code\u003e,\nplus the following:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003ehas(e.f)\u003c/code\u003e: Space is constant.\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eIf \u003ccode\u003ee\u003c/code\u003e is a map, time is linear in size of \u003ccode\u003ee\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eIf \u003ccode\u003ee\u003c/code\u003e is a message, time is constant.\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ee.all(x, p)\u003c/code\u003e, \u003ccode\u003ee.exists(x, p)\u003c/code\u003e, and \u003ccode\u003ee.exists_one(x, p)\u003c/code\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eTime is the sum of the time of \u003ccode\u003ep\u003c/code\u003e for each element of \u003ccode\u003ee\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eSpace is constant.\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ee.map(x, t)\u003c/code\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eTime is the sum of time of \u003ccode\u003et\u003c/code\u003e for each element of \u003ccode\u003ee\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eSpace is the sum of space of \u003ccode\u003et\u003c/code\u003e for each element of \u003ccode\u003ee\u003c/code\u003e, plus a\nconstant.\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ee.filter(x, t)\u003c/code\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eTime is the sum of time of \u003ccode\u003et\u003c/code\u003e for each element of \u003ccode\u003ee\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eSpace is the space of \u003ccode\u003ee\u003c/code\u003e.\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003ePerformance Limits\u003c/h3\u003e\u003ca id=\"user-content-performance-limits\" class=\"anchor\" aria-label=\"Permalink: Performance Limits\" href=\"#performance-limits\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003ePutting this all together, we can make the following statements about the cost\nof evaluation. Let \u003ccode\u003eP\u003c/code\u003e be the non-literal size of the expression, \u003ccode\u003eL\u003c/code\u003e be the\nsize of the literals, \u003ccode\u003eB\u003c/code\u003e be the size of the bindings, and \u003ccode\u003eI=B+L\u003c/code\u003e be the total\nsize of the inputs.\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eThe macros other than \u003ccode\u003ehas()\u003c/code\u003e are the only avenue for exponential\nbehavior. This can be curtailed by the implementation allowing applications\nto set limits on the recursion or chaining of macros, or disable them\nentirely.\u003c/li\u003e\n\u003cli\u003eThe concatenation operator \u003ccode\u003e_+_\u003c/code\u003e is the only operator that dramatically\nincreases the space complexity, with the program \u003ccode\u003ex + x + ... + x\u003c/code\u003e taking\ntime and space \u003ccode\u003eO(B * P^2)\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eThe string-detection functions (\u003ccode\u003econtains()\u003c/code\u003e and friends) yield a boolean\nresult, thus cannot be nested to drive exponential or even higher\npolynomial cost. We can bound the time cost by \u003ccode\u003eO(B^2 * P)\u003c/code\u003e, with a\nlimiting case being \u003ccode\u003ex.contains(y) || x.contains(y) || ...\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eThe map indexing operators yield a smaller result than their input, and\nthus are also limited in their ability to increase the cost. A particularly\nbad case would be an expensive selection that returns a subcomponent that\ncontains the majority of the size of the aggregate, resulting in a time\ncost of \u003ccode\u003eO(P * I)\u003c/code\u003e, and see below.\u003c/li\u003e\n\u003cli\u003eEliminating all of the above and using only default-cost functions, plus\naggregate literals, time and space are limited \u003ccode\u003eO(P * I)\u003c/code\u003e.\nA limiting time example is \u003ccode\u003esize(x) + size(x) + ...\u003c/code\u003e.\nA limiting time and space example is \u003ccode\u003e[x, x, ..., x]\u003c/code\u003e.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003eNote that custom function will alter this analysis if they are more expensive\nthan the default costs.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eFunctions\u003c/h2\u003e\u003ca id=\"user-content-functions\" class=\"anchor\" aria-label=\"Permalink: Functions\" href=\"#functions\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eCEL functions have no observable side effects (there may be side effects like\nlogging or such which are not observable from CEL). The default argument\nevaluation strategy for functions is strict, with exceptions from this rule\ndiscussed in \u003ca href=\"#logical-operators\"\u003eLogical Operators\u003c/a\u003e and \u003ca href=\"#macros\"\u003eMacros\u003c/a\u003e.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eFunctions are specified by a set of overloads. Each overload defines the number\nand type of arguments and the type of the result, as well as an opaque\ncomputation. Argument and result types can use type variables to express\noverloads which work on lists and maps. At runtime, a matching overload is\nselected and the according computation invoked. If no overload matches, the\nruntime error \u003ccode\u003eno_matching_overload\u003c/code\u003e is raised (see also\n\u003ca href=\"#errors\"\u003eRuntime Errors\u003c/a\u003e). For example, the standard function \u003ccode\u003esize\u003c/code\u003e is\nspecified by the following overloads:\u003c/p\u003e\n\u003cmarkdown-accessiblity-table\u003e\u003ctable border=\"1\"\u003e\n \u003ctbody\u003e\u003ctr\u003e\n \u003cth rowspan=\"4\"\u003e\n size\n \u003c/th\u003e\n \u003ctd\u003e\n (string) -\u0026gt; int\n \u003c/td\u003e\n \u003ctd\u003e\n string length\n \u003c/td\u003e\n \u003c/tr\u003e\n \u003ctr\u003e\n \u003ctd\u003e\n (bytes) -\u0026gt; int\n \u003c/td\u003e\n \u003ctd\u003e\n bytes length\n \u003c/td\u003e\n \u003c/tr\u003e\n \u003ctr\u003e\n \u003ctd\u003e\n (list(A)) -\u0026gt; int\n \u003c/td\u003e\n \u003ctd\u003e\n list size\n \u003c/td\u003e\n \u003c/tr\u003e\n \u003ctr\u003e\n \u003ctd\u003e\n (map(A, B)) -\u0026gt; int\n \u003c/td\u003e\n \u003ctd\u003e\n map size\n \u003c/td\u003e\n \u003c/tr\u003e\n\u003c/tbody\u003e\u003c/table\u003e\u003c/markdown-accessiblity-table\u003e\n\u003cp dir=\"auto\"\u003eOverloads must have non-overlapping argument types, after erasure of all type\nvariables (similar as type erasure in Java). Thus an implementation can\nimplement overload resolution by simply mapping all argument types to a strong\nhash.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eOperator sub-expressions are treated as calls to specially-named built-in\nfunctions. For instance, the expression \u003ccode\u003ee1 + e2\u003c/code\u003e is dispatched to the function\n\u003ccode\u003e_+_\u003c/code\u003e with arguments \u003ccode\u003ee1\u003c/code\u003e and \u003ccode\u003ee2\u003c/code\u003e. Note that since \u003ccode\u003e_+_\u003c/code\u003e is not an identifier,\nthere would be no way to write this as a normal function call.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eSee \u003ca href=\"#standard-definitions\"\u003eStandard Definitions\u003c/a\u003e for the list of all predefined\nfunctions and operators.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eExtension Functions\u003c/h3\u003e\u003ca id=\"user-content-extension-functions\" class=\"anchor\" aria-label=\"Permalink: Extension Functions\" href=\"#extension-functions\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eIt is possible to add extension functions to CEL, which then behave consistently\nwith standard functions. The mechanism for doing this is implementation\ndependent and usually highly curated. For example, an application domain of CEL\ncan add a new overload to the \u003ccode\u003esize\u003c/code\u003e function above, provided this overload's\nargument types do not overlap with any existing overload. For methodological\nreasons, CEL does not allow overloading operators.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eLike standard functions, extension functions must be free from observable side\neffects in order to prevent expressions from having undefined results, since CEL\ndoes not guarantee evaluation order of sub-expressions.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eReceiver Call Style\u003c/h3\u003e\u003ca id=\"user-content-receiver-call-style\" class=\"anchor\" aria-label=\"Permalink: Receiver Call Style\" href=\"#receiver-call-style\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eA function overload can be declared to use receiver call-style, so it must be\ncalled as \u003ccode\u003ee1.f(e2)\u003c/code\u003e instead of \u003ccode\u003ef(e1, e2)\u003c/code\u003e. Overloads with different call\nstyles are non-overlapping per definition, regardless of their types.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eStandard Definitions\u003c/h2\u003e\u003ca id=\"user-content-standard-definitions\" class=\"anchor\" aria-label=\"Permalink: Standard Definitions\" href=\"#standard-definitions\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eAll predefined operators, functions and constants are listed in the table below.\nFor each symbol, the available overloads are listed. Operator symbols use a\nnotation like \u003ccode\u003e_+_\u003c/code\u003e where \u003ccode\u003e_\u003c/code\u003e is a placeholder for an argument.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eEquality\u003c/h3\u003e\u003ca id=\"user-content-equality\" class=\"anchor\" aria-label=\"Permalink: Equality\" href=\"#equality\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eEquality (\u003ccode\u003e_==_\u003c/code\u003e) and inequality (\u003ccode\u003e_!=_\u003c/code\u003e) are defined for all types. Inequality\nis the logical negation of equality, i.e. \u003ccode\u003ee1 != e2\u003c/code\u003e is the same as\n\u003ccode\u003e!(e1 == e2)\u003c/code\u003e for all expressions \u003ccode\u003ee1\u003c/code\u003e and \u003ccode\u003ee2\u003c/code\u003e.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eType-checking asserts that arguments to equality operators must be the same\ntype. If the argument types differ, the type-checker will raise an error.\nHowever, if at least one argument is dynamically typed, the type-checker\nconsiders all arguments dynamic and defers type-agreement checks to the\ninterpreter.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThe type-checker uses homogeneous equality to surface potential logical errors\nduring static analysis, but the runtime uses heterogeneous equality with\na definition of \u003ca href=\"#Numbers\"\u003enumeric equality\u003c/a\u003e which treats all numeric types as\nthough they exist on a continuous number line. Semantically, equality would be\nexpressed within in CEL as follows:\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"type(x) in [double, int, uint]\n \u0026amp;\u0026amp; type(y) in [double, int, uint] ? numericEquals(x, y)\n : type(x) == type(y) ? x == y\n : false\"\u003e\u003cpre lang=\"cel\" class=\"notranslate\"\u003e\u003ccode\u003etype(x) in [double, int, uint]\n \u0026amp;\u0026amp; type(y) in [double, int, uint] ? numericEquals(x, y)\n : type(x) == type(y) ? x == y\n : false\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eCEL's support for boxed primitives relies on heterogeneous equality to ensure\nthat comparisons to \u003ccode\u003enull\u003c/code\u003e evaluate to \u003ccode\u003etrue\u003c/code\u003e or \u003ccode\u003efalse\u003c/code\u003e rather than error.\nThis behavior is also useful for evaluating JSON data where all numbers may\nbe provided as \u003ccode\u003edouble\u003c/code\u003e or, depending on the underlying JSON implementation,\npossibly \u003ccode\u003eint\u003c/code\u003e. This potential discrepancy between how runtimes handle dynamic\ndata is further motivation for supporting separate behaviors at type-check and\ninterpretation.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eNumbers\u003c/h4\u003e\u003ca id=\"user-content-numbers\" class=\"anchor\" aria-label=\"Permalink: Numbers\" href=\"#numbers\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThe numeric types of \u003ccode\u003eint\u003c/code\u003e, \u003ccode\u003euint\u003c/code\u003e, and \u003ccode\u003edouble\u003c/code\u003e are compared as though they\nexist on a continuous number line where two numbers \u003ccode\u003ex\u003c/code\u003e and \u003ccode\u003ey\u003c/code\u003e are equal if\n\u003ccode\u003e!(x \u0026lt; y || x \u0026gt; y)\u003c/code\u003e. Since it is possible to compare numeric types without\ntype conversion, CEL uses this definition for \u003ccode\u003enumericEquals\u003c/code\u003e to support\ncomparison across numeric types.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThis property of cross-type numeric equality is essential for supporting\nJSON in a way which mostly closely matches user expectations. The following\nexpressions are equivalent as the type-checker cannot infer the type of the\n\u003ccode\u003ejson.number\u003c/code\u003e in the expression since it is considered \u003ccode\u003edyn\u003c/code\u003e typed:\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eIndex into a map:\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"{1: 'hello', 2: 'world'}[json.number]\n{1: 'hello', 2: 'world'}[int(json.number)]\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003e{1: 'hello', 2: 'world'}[json.number]\n{1: 'hello', 2: 'world'}[int(json.number)]\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eSet membership test of a json number in a list of integers:\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"json.number in [1, 2, 3]\nint(json.number) in [1, 2, 3]\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003ejson.number in [1, 2, 3]\nint(json.number) in [1, 2, 3]\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThe \u003ccode\u003edouble\u003c/code\u003e type follows the IEEE 754 standard. Not-a-number (\u003ccode\u003eNaN\u003c/code\u003e) values\ncompare as unequal, e.g. \u003ccode\u003eNaN == NaN // false\u003c/code\u003e and \u003ccode\u003eNaN != NaN // true\u003c/code\u003e.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eLists and Maps\u003c/h4\u003e\u003ca id=\"user-content-lists-and-maps\" class=\"anchor\" aria-label=\"Permalink: Lists and Maps\" href=\"#lists-and-maps\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eTwo \u003ccode\u003elist\u003c/code\u003e values equal if their entries at each ordinal are equal. For lists\n\u003ccode\u003ea\u003c/code\u003e and \u003ccode\u003eb\u003c/code\u003e with length \u003ccode\u003eN\u003c/code\u003e, \u003ccode\u003ea == b\u003c/code\u003e is equivalent to:\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"a[0] == b[0] \u0026amp;\u0026amp; a[1] == b[1] \u0026amp;\u0026amp; ... \u0026amp;\u0026amp; a[N-1] == b[N-1]\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003ea[0] == b[0] \u0026amp;\u0026amp; a[1] == b[1] \u0026amp;\u0026amp; ... \u0026amp;\u0026amp; a[N-1] == b[N-1]\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eTwo \u003ccode\u003emap\u003c/code\u003e values are equal if their entries are the same. For maps \u003ccode\u003ea\u003c/code\u003e and \u003ccode\u003eb\u003c/code\u003e\nwith keyset \u003ccode\u003ek1, k2, ..., kN\u003c/code\u003e, \u003ccode\u003ea == b\u003c/code\u003e equality is equivalent to:\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"a[k1] == b[k1] \u0026amp;\u0026amp; a[k2] == b[k2] \u0026amp;\u0026amp; ... \u0026amp;\u0026amp; a[kN] == b[kN]\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003ea[k1] == b[k1] \u0026amp;\u0026amp; a[k2] == b[k2] \u0026amp;\u0026amp; ... \u0026amp;\u0026amp; a[kN] == b[kN]\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eIn short, when \u003ccode\u003elist\u003c/code\u003e lengths / \u003ccode\u003emap\u003c/code\u003e key sets are the same, and all element\ncomparisons are \u003ccode\u003etrue\u003c/code\u003e, the result is \u003ccode\u003etrue\u003c/code\u003e.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eProtocol Buffers\u003c/h4\u003e\u003ca id=\"user-content-protocol-buffers\" class=\"anchor\" aria-label=\"Permalink: Protocol Buffers\" href=\"#protocol-buffers\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eCEL uses the C++ \u003ca href=\"https://developers.google.com/protocol-buffers/docs/reference/cpp/google.protobuf.util.message_differencer#MessageDifferencer.Equals.details\" rel=\"nofollow\"\u003e\u003ccode\u003eMessageDifferencer::Equals\u003c/code\u003e\u003c/a\u003e\nsemantics for comparing Protocol Buffer messages across all runtimes. For two\nmessages to be equal:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eBoth messages must share the same type name and \u003ccode\u003eDescriptor\u003c/code\u003e instance;\u003c/li\u003e\n\u003cli\u003eBoth messages must have the same set fields;\u003c/li\u003e\n\u003cli\u003eAll primitive typed fields compare equal by value, e.g. \u003ccode\u003estring\u003c/code\u003e, \u003ccode\u003eint64\u003c/code\u003e;\u003c/li\u003e\n\u003cli\u003eAll elements of \u003ccode\u003erepeated\u003c/code\u003e fields compare in-order as \u003ccode\u003etrue\u003c/code\u003e;\u003c/li\u003e\n\u003cli\u003eAll entries of \u003ccode\u003emap\u003c/code\u003e fields compare order-independently as \u003ccode\u003etrue\u003c/code\u003e;\u003c/li\u003e\n\u003cli\u003eAll fields of \u003ccode\u003emessage\u003c/code\u003e and \u003ccode\u003egroup\u003c/code\u003e typed fields compare true, with the\ncomparison being performed as if by recursion.\u003c/li\u003e\n\u003cli\u003eAll unknown fields compare \u003ccode\u003etrue\u003c/code\u003e using byte equality.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003eIn addition to the publicly documented behaviors for C++ protobuf equality,\nthere are some implementation behaviors which are important to mention:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eThe \u003ccode\u003edouble\u003c/code\u003e type follows the IEEE 754 standard where not-a-number (\u003ccode\u003eNaN\u003c/code\u003e)\nvalues compare as unequal, e.g. \u003ccode\u003eNaN == NaN // false\u003c/code\u003e and\n\u003ccode\u003eNaN != NaN // true\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eAll \u003ccode\u003egoogle.protobuf.Any\u003c/code\u003e typed fields are unpacked before comparison,\nunless the \u003ccode\u003etype_url\u003c/code\u003e cannot be resolved, in which case the comparison\nfalls back to byte equality.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003eProtocol buffer equality semantics in C++ are generally consistent with CEL's\ndefinition of heterogeneous equality. Note, Java and Go proto equality\nimplementations do not follow IEEE 754 for \u003ccode\u003eNaN\u003c/code\u003e values and do not unpack\n\u003ccode\u003egoogle.protobuf.Any\u003c/code\u003e values before comparison. These comparison differences\ncan result in false negatives or false positives; consequently, CEL provides\na uniform definition across runtimes to ensure consistent evaluation across\nruntimes.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThere is one edge case where CEL and protobuf equality will produce\ndifferent results; however, this edge case is sufficiently unlikely that\nthe difference is acceptable:\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"// Protocol buffer definition\nmessage Msg {\n repeated google.protobuf.Any values;\n}\n\n// CEL - Produces `false` according to protobuf equality since the types of\n// Int32Value and FloatValue are not equal.\nMsg{values: [google.protobuf.Int32Value{value: 1}]}\n == Msg{values: [google.protobuf.FloatValue{value: 1.0}]}\n\n// CEL - Produces `true` according to CEL equality with well-known\n// protobuf type unwrapping of the list elements within `values`\n// where the list values are unwrapped to CEL numbers and compared\n// using `numericEquals`.\nMsg{values: [google.protobuf.Int32Value{value: 1}]}.values\n == Msg{values: [google.protobuf.FloatValue{value: 1.0}]}.values\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003e// Protocol buffer definition\nmessage Msg {\n repeated google.protobuf.Any values;\n}\n\n// CEL - Produces `false` according to protobuf equality since the types of\n// Int32Value and FloatValue are not equal.\nMsg{values: [google.protobuf.Int32Value{value: 1}]}\n == Msg{values: [google.protobuf.FloatValue{value: 1.0}]}\n\n// CEL - Produces `true` according to CEL equality with well-known\n// protobuf type unwrapping of the list elements within `values`\n// where the list values are unwrapped to CEL numbers and compared\n// using `numericEquals`.\nMsg{values: [google.protobuf.Int32Value{value: 1}]}.values\n == Msg{values: [google.protobuf.FloatValue{value: 1.0}]}.values\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eOrdering\u003c/h3\u003e\u003ca id=\"user-content-ordering\" class=\"anchor\" aria-label=\"Permalink: Ordering\" href=\"#ordering\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eOrdering operators are defined for \u003ccode\u003eint\u003c/code\u003e, \u003ccode\u003euint\u003c/code\u003e, \u003ccode\u003edouble\u003c/code\u003e, \u003ccode\u003estring\u003c/code\u003e, \u003ccode\u003ebytes\u003c/code\u003e,\n\u003ccode\u003ebool\u003c/code\u003e, as well as \u003ccode\u003etimestamp\u003c/code\u003e and \u003ccode\u003eduration\u003c/code\u003e. Runtime ordering is also\nsupported across \u003ccode\u003eint\u003c/code\u003e, \u003ccode\u003euint\u003c/code\u003e, and \u003ccode\u003edouble\u003c/code\u003e for consistency with the runtime\nequality definition for numeric types.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eStrings and bytes obey lexicographic ordering of the byte values. Because\nstrings are encoded in UTF-8, strings consequently also obey lexicographic\nordering of their Unicode code points.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThe ordering operators obey the usual algebraic properties, i.e. \u003ccode\u003ee1 \u0026lt;= e2\u003c/code\u003e\ngives the same result as \u003ccode\u003e!(e1 \u0026gt; e2)\u003c/code\u003e as well as \u003ccode\u003e(e1 \u0026lt; e2) || (e1 == e2)\u003c/code\u003e.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eOverflow\u003c/h3\u003e\u003ca id=\"user-content-overflow\" class=\"anchor\" aria-label=\"Permalink: Overflow\" href=\"#overflow\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eArithmetic operations raise an error when the results exceed the range of the\ninteger type (int, uint) or the timestamp or duration type. An error is also\nraised for conversions which exceed the range of the target type.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThere are a few additional considerations to keep in mind with respect to\nhow and when certain types will overflow:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eDuration values are limited to a single int64 value, or roughly +-290 years.\u003c/li\u003e\n\u003cli\u003eTimestamp values are limited to the range of values which can be serialized\nas a string: [\"0001-01-01T00:00:00Z\", \"9999-12-31T23:59:59.999999999Z\"].\u003c/li\u003e\n\u003cli\u003eDouble to int conversions are limited to (minInt, maxInt) non-inclusive.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003eNote, that whether the minimum or maximum integer value will roundtrip successfully\nint -\u0026gt; double -\u0026gt; int can be compiler dependent which is the motivation for the\nconservative round-tripping behavior.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eTimezones\u003c/h3\u003e\u003ca id=\"user-content-timezones\" class=\"anchor\" aria-label=\"Permalink: Timezones\" href=\"#timezones\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eTimezones are expressed in the following grammar:\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"TimeZone = \u0026quot;UTC\u0026quot; | LongTZ | FixedTZ ;\nLongTZ = ? list available at\n https://www.joda.org/joda-time/timezones.html ? ;\nFixedTZ = ( \u0026quot;+\u0026quot; | \u0026quot;-\u0026quot; ) Digit Digit \u0026quot;:\u0026quot; Digit Digit ;\nDigit = \u0026quot;0\u0026quot; | \u0026quot;1\u0026quot; | ... | \u0026quot;9\u0026quot; ;\"\u003e\u003cpre lang=\"grammar\" class=\"notranslate\"\u003e\u003ccode\u003eTimeZone = \"UTC\" | LongTZ | FixedTZ ;\nLongTZ = ? list available at\n https://www.joda.org/joda-time/timezones.html ? ;\nFixedTZ = ( \"+\" | \"-\" ) Digit Digit \":\" Digit Digit ;\nDigit = \"0\" | \"1\" | ... | \"9\" ;\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eFixed timezones are explicit hour and minute offsets from UTC. Long timezone\nnames are like \u003ccode\u003eEurope/Paris\u003c/code\u003e, \u003ccode\u003eCET\u003c/code\u003e, or \u003ccode\u003eUS/Central\u003c/code\u003e.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eRegular Expressions\u003c/h3\u003e\u003ca id=\"user-content-regular-expressions\" class=\"anchor\" aria-label=\"Permalink: Regular Expressions\" href=\"#regular-expressions\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eRegular expressions follow the\n\u003ca href=\"https://github.com/google/re2/wiki/Syntax\"\u003eRE2 syntax\u003c/a\u003e. Regular expression\nmatches succeed if they match a substring of the argument. Use explicit anchors\n(\u003ccode\u003e^\u003c/code\u003e and \u003ccode\u003e$\u003c/code\u003e) in the pattern to force full-string matching, if desired.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eStandard Environment\u003c/h3\u003e\u003ca id=\"user-content-standard-environment\" class=\"anchor\" aria-label=\"Permalink: Standard Environment\" href=\"#standard-environment\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003ePresence and Comprehension Macros\u003c/h4\u003e\u003ca id=\"user-content-presence-and-comprehension-macros\" class=\"anchor\" aria-label=\"Permalink: Presence and Comprehension Macros\" href=\"#presence-and-comprehension-macros\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003ehas(message.field)\u003c/strong\u003e - Checks if a field exists within a message. This macro\nsupports proto2, proto3, and map key accesses. Only map accesses using the\nselect notation are supported.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eSignatures\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003ehas(message.field) -\u0026gt; bool\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eExamples\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"// `true` if the 'address' field exists in the 'user' message\nhas(user.address)\n// `true` if map 'm' has a key named 'key_name' defined. The value may be null\n// as null does not connote absence in CEL.\nhas(m.key_name)\n// `false` if the 'items' field is not set in the 'order' message\nhas(order.items)\n// `false` if the 'user_id' key is not present in the 'sessions' map has(sessions.user_id)\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003e// `true` if the 'address' field exists in the 'user' message\nhas(user.address)\n// `true` if map 'm' has a key named 'key_name' defined. The value may be null\n// as null does not connote absence in CEL.\nhas(m.key_name)\n// `false` if the 'items' field is not set in the 'order' message\nhas(order.items)\n// `false` if the 'user_id' key is not present in the 'sessions' map has(sessions.user_id)\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eall -\u003c/strong\u003e Tests whether all elements in the input list or all keys in a map\nsatisfy the given predicate. The all macro behaves in a manner consistent with\nthe Logical AND operator including in how it absorbs errors and short-circuits.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eSignatures\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003elist(A).all(A, predicate(A) -\u0026gt; bool) -\u0026gt; bool\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003emap(A, B).all(A, predicate(A) -\u0026gt; bool) -\u0026gt; bool\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eExamples\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"[1, 2, 3].all(x, x \u0026gt; 0) // true\n[1, 2, 0].all(x, x \u0026gt; 0) // false\n['apple', 'banana', 'cherry'].all(fruit, fruit.size() \u0026gt; 3) // true\n[3.14, 2.71, 1.61].all(num, num \u0026lt; 3.0) // false\n{'a': 1, 'b': 2, 'c': 3}.all(key, key != 'b') // false\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003e[1, 2, 3].all(x, x \u0026gt; 0) // true\n[1, 2, 0].all(x, x \u0026gt; 0) // false\n['apple', 'banana', 'cherry'].all(fruit, fruit.size() \u0026gt; 3) // true\n[3.14, 2.71, 1.61].all(num, num \u0026lt; 3.0) // false\n{'a': 1, 'b': 2, 'c': 3}.all(key, key != 'b') // false\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eexists\u003c/strong\u003e - Tests whether any value in the list or any key in the map\nsatisfies the predicate expression. The exists macro behaves in a manner\nconsistent with the Logical OR operator including in how it absorbs errors and\nshort-circuits.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eSignatures\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003elist(A).exists(A, predicate(A) -\u0026gt; bool) -\u0026gt; bool\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003emap(A,B).exists(A, predicate(A) -\u0026gt; bool) -\u0026gt; bool\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eExamples\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"[1, 2, 3].exists(i, i % 2 != 0) // true\n[].exists(i, i \u0026gt; 0) // false\n[0, -1, 5].exists(num, num \u0026lt; 0) // true\n{'x': 'foo', 'y': 'bar'}.exists(key, key.startsWith('z')) // false\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003e[1, 2, 3].exists(i, i % 2 != 0) // true\n[].exists(i, i \u0026gt; 0) // false\n[0, -1, 5].exists(num, num \u0026lt; 0) // true\n{'x': 'foo', 'y': 'bar'}.exists(key, key.startsWith('z')) // false\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eexists_one\u003c/strong\u003e - Tests whether exactly one list element or map key satisfies\nthe predicate expression. This macro does not short-circuit in order to remain\nconsistent with logical operators being the only operators which can absorb\nerrors within CEL.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eSignatures\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003elist(A).exists_one(A, predicate(A)) -\u0026gt; bool\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003emap(A,B).exists_one(A, predicate(A)) -\u0026gt; bool\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eExamples\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"[1, 2, 2].exists_one(i, i \u0026lt; 2) // true\n{'a': 'hello', 'aa': 'hellohello'}.exists_one(k, k.startsWith('a')) // false\n[1, 2, 3, 4].exists_one(num, num % 2 == 0) // false\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003e[1, 2, 2].exists_one(i, i \u0026lt; 2) // true\n{'a': 'hello', 'aa': 'hellohello'}.exists_one(k, k.startsWith('a')) // false\n[1, 2, 3, 4].exists_one(num, num % 2 == 0) // false\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003efilter\u003c/strong\u003e - Returns a list containing only the elements from the input list\nthat satisfy the given predicate\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eSignatures\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003elist(A).filter(A, function(A) -\u0026gt; bool) -\u0026gt; list(A)\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003emap(A, B).filter(A, function(A) -\u0026gt; bool) -\u0026gt; list(A)\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eExamples\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"[1, 2, 3].filter(x, x \u0026gt; 1) // [2, 3]\n['cat', 'dog', 'bird', 'fish'].filter(pet, pet.size() == 3) // ['cat', 'dog']\n[{'a': 10, 'b': 5, 'c': 20}].map(m, m.filter(key, m[key] \u0026gt; 10)) // [['c']]\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003e[1, 2, 3].filter(x, x \u0026gt; 1) // [2, 3]\n['cat', 'dog', 'bird', 'fish'].filter(pet, pet.size() == 3) // ['cat', 'dog']\n[{'a': 10, 'b': 5, 'c': 20}].map(m, m.filter(key, m[key] \u0026gt; 10)) // [['c']]\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003emap\u003c/strong\u003e - Returns a list where each element is the result of applying the\ntransform expression to the corresponding input list element or input map key.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThere are two forms of the map macro:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eThe three argument form transforms all elements.\u003c/li\u003e\n\u003cli\u003eThe four argument form transforms only elements which satisfy the predicate.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003eThe four argument form of the macro exists to simplify combined filter / map\noperations.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eSignatures\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003elist(A).map(A, function(A) -\u0026gt; T) -\u0026gt; list(T)\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003elist(A).map(A, function(A) -\u0026gt; bool, function(A) -\u0026gt; T) -\u0026gt; list(T)\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003emap(A, B).map(A, function(A) -\u0026gt; T) -\u0026gt; list(T)\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003emap(A, B).map(A, function(A) -\u0026gt; bool, function(A) -\u0026gt; T) -\u0026gt; list(T)\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eExamples\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"[1, 2, 3].map(x, x * 2) // [2, 4, 6]\n[5, 10, 15].map(x, x / 5) // [1, 2, 3]\n['apple', 'banana'].map(fruit, fruit.upperAscii()) // ['APPLE', 'BANANA']\n[1, 2, 3, 4].map(num, num % 2 == 0, num * 2) // [4, 8]\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003e[1, 2, 3].map(x, x * 2) // [2, 4, 6]\n[5, 10, 15].map(x, x / 5) // [1, 2, 3]\n['apple', 'banana'].map(fruit, fruit.upperAscii()) // ['APPLE', 'BANANA']\n[1, 2, 3, 4].map(num, num % 2 == 0, num * 2) // [4, 8]\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eLogical Operators\u003c/h4\u003e\u003ca id=\"user-content-logical-operators-1\" class=\"anchor\" aria-label=\"Permalink: Logical Operators\" href=\"#logical-operators-1\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eLogical NOT (!)\u003c/strong\u003e - Takes a boolean value as input and returns the opposite\nboolean value.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eSignatures:\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003e!bool -\u0026gt; bool\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eExamples:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"!true // false\n!false // true\n!error // error\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003e!true // false\n!false // true\n!error // error\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eLogical OR (||)\u003c/strong\u003e - Compute the logical OR of two or more values. Errors and\nunknown values are considered valid inputs to this operator and will not halt\nevaluation.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eSignatures:\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003ebool || bool -\u0026gt; bool\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eExamples:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"true || false // true\nfalse || false // false\nerror || true // true\nerror || false // error\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003etrue || false // true\nfalse || false // false\nerror || true // true\nerror || false // error\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eLogical AND (\u0026amp;\u0026amp;)\u003c/strong\u003e - Compute the logical AND of two or more values. Errors\nand unknown values are considered valid inputs to this operator and will not\nhalt evaluation.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eSignatures:\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003ebool \u0026amp;\u0026amp; bool -\u0026gt; bool\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eExamples:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"true \u0026amp;\u0026amp; true // true\ntrue \u0026amp;\u0026amp; false // false\nerror \u0026amp;\u0026amp; true // error\nerror \u0026amp;\u0026amp; false // false\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003etrue \u0026amp;\u0026amp; true // true\ntrue \u0026amp;\u0026amp; false // false\nerror \u0026amp;\u0026amp; true // error\nerror \u0026amp;\u0026amp; false // false\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eConditional Operator (? : )\u003c/strong\u003e - The conditional or ternary operator which\nevaluates the test condition and only one of the remaining sub-expressions\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eSignatures:\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003ebool ? A : A -\u0026gt; A\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eExamples:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"true ? 1 : 2 // 1\nfalse ? \u0026quot;a\u0026quot; : \u0026quot;b\u0026quot; // \u0026quot;b\u0026quot;\ntrue ? error : value // error\nfalse ? error : value // value\n(2 \u0026lt; 5) ? 'yes' : 'no' // 'yes'\n('hello'.size() \u0026gt; 10) ? 1 / 0 : 42 // 42\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003etrue ? 1 : 2 // 1\nfalse ? \"a\" : \"b\" // \"b\"\ntrue ? error : value // error\nfalse ? error : value // value\n(2 \u0026lt; 5) ? 'yes' : 'no' // 'yes'\n('hello'.size() \u0026gt; 10) ? 1 / 0 : 42 // 42\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eNote:\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003eerror\u003c/code\u003e is a special value in CEL that represents an error condition.\nOperations involving \u003ccode\u003eerror\u003c/code\u003e typically propagate the error.\u003c/li\u003e\n\u003cli\u003eThis documentation provides examples for a few CEL operators. The complete\nCEL specification includes many more operators and functions.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eArithmetic Operators\u003c/h4\u003e\u003ca id=\"user-content-arithmetic-operators\" class=\"anchor\" aria-label=\"Permalink: Arithmetic Operators\" href=\"#arithmetic-operators\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eNegation (-)\u003c/strong\u003e - Takes a numeric value (int or double) as input and returns\nits negated value.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eSignatures:\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003e-int -\u0026gt; int\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003e-double -\u0026gt; double\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eExamples:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"-5 // -5\n-3.14 // -3.14\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003e-5 // -5\n-3.14 // -3.14\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eAddition (+)\u003c/strong\u003e - Adds two numeric values or concatenates two strings, bytes,\nor lists.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eSignatures:\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eNumeric addition\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003eint + int -\u0026gt; int\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003euint + uint -\u0026gt; uint\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003edouble + double -\u0026gt; double\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eTime and duration addition\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003egoogle.protobuf.Timestamp + google.protobuf.Duration -\u0026gt; google.protobuf.Timestamp\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003egoogle.protobuf.Duration + google.protobuf.Timestamp -\u0026gt; google.protobuf.Timestamp\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003egoogle.protobuf.Duration + google.protobuf.Duration -\u0026gt; google.protobuf.Duration\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eConcatenation\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003estring + string -\u0026gt; string\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ebytes + bytes -\u0026gt; bytes\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003elist(A) + list(A) -\u0026gt; list(A)\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eExamples:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"1 + 2 // 3\n3.14 + 1.59 // 4.73\n\u0026quot;Hello, \u0026quot; + \u0026quot;world!\u0026quot; // \u0026quot;Hello, world!\u0026quot;\n[1] + [2, 3] // [1, 2, 3]\nduration('1m') + duration('1s') // duration('1m1s')\ntimestamp('2023-01-01T00:00:00Z')\n + duration('24h') // timestamp('2023-01-02T00:00:00Z')\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003e1 + 2 // 3\n3.14 + 1.59 // 4.73\n\"Hello, \" + \"world!\" // \"Hello, world!\"\n[1] + [2, 3] // [1, 2, 3]\nduration('1m') + duration('1s') // duration('1m1s')\ntimestamp('2023-01-01T00:00:00Z')\n + duration('24h') // timestamp('2023-01-02T00:00:00Z')\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eSubtraction (-)\u003c/strong\u003e - Subtracts two numeric values or calculates the duration\nbetween two timestamps.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eSignatures:\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eNumeric subtraction\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003eint - int -\u0026gt; int\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003euint - uint -\u0026gt; uint\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003edouble - double -\u0026gt; double\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eTime and duration subtraction\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003egoogle.protobuf.Timestamp - google.protobuf.Timestamp -\u0026gt; google.protobuf.Duration\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003egoogle.protobuf.Timestamp - google.protobuf.Duration -\u0026gt; google.protobuf.Timestamp\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003egoogle.protobuf.Duration - google.protobuf.Duration -\u0026gt; google.protobuf.Duration\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eExamples:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"5 - 3 // 2\n10.5 - 2.0 // 8.5\nduration('1m') - duration('1s') // duration('59s')\ntimestamp('2023-01-10T12:00:00Z')\n - timestamp('2023-01-10T00:00:00Z') // duration('12h')\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003e5 - 3 // 2\n10.5 - 2.0 // 8.5\nduration('1m') - duration('1s') // duration('59s')\ntimestamp('2023-01-10T12:00:00Z')\n - timestamp('2023-01-10T00:00:00Z') // duration('12h')\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eDivision (/)\u003c/strong\u003e - Divides two numeric values.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eSignatures:\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003eint / int -\u0026gt; int\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003euint / uint -\u0026gt; uint\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003edouble / double -\u0026gt; double\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eExamples:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"10 / 2 // 5\n7.0 / 2.0 // 3.5\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003e10 / 2 // 5\n7.0 / 2.0 // 3.5\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eComparison Operators\u003c/h4\u003e\u003ca id=\"user-content-comparison-operators\" class=\"anchor\" aria-label=\"Permalink: Comparison Operators\" href=\"#comparison-operators\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eComparisons require strict type equality at type-check time. If types do not\nagree, then type-conversion is required in order to be explicit about the\nintention and inherent risks of comparing across types.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThe one exception to this rule is numeric comparisons at runtime. Since CEL\nsupports JSON in addition to Protocol Buffers, it must handle cases where the\nuser intent was to compare an integer value to a JSON value within the int53\nrange. For this reason, numeric comparisons across type are supported at\nruntime as all numeric representations may be considered to exist along a\nshared number line independent of their representation in memory.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eEquality (==)\u003c/strong\u003e - Compares two values of the same type and returns \u003ccode\u003etrue\u003c/code\u003e if\nthey are equal, and \u003ccode\u003efalse\u003c/code\u003e otherwise\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eSignatures:\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003eA == A -\u0026gt; bool\u003c/code\u003e (where A can be any comparable type)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eExamples:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"1 == 1 // true\n\u0026quot;hello\u0026quot; == \u0026quot;world\u0026quot; // false\nbytes('hello') == b'hello' // true\nduration('1h') == duration('60m') // true\ndyn(3.0) == 3 // true\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003e1 == 1 // true\n\"hello\" == \"world\" // false\nbytes('hello') == b'hello' // true\nduration('1h') == duration('60m') // true\ndyn(3.0) == 3 // true\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eInequality (!=)\u003c/strong\u003e - Takes two values of the same type and returns \u003ccode\u003etrue\u003c/code\u003e if\nthey are not equal, and \u003ccode\u003efalse\u003c/code\u003e otherwise.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eSignatures:\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003eA != A -\u0026gt; bool\u003c/code\u003e (where A can be any comparable type)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eExamples:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"1 != 2     // true\n\u0026quot;a\u0026quot; != \u0026quot;a\u0026quot; // false\n3.0 != 3.1 // true\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003e1 != 2     // true\n\"a\" != \"a\" // false\n3.0 != 3.1 // true\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eLess Than or Equal To (\u0026lt;=)\u003c/strong\u003e - Compares two values and returns \u003ccode\u003etrue\u003c/code\u003e if the\nfirst value is less than or equal to the second value, and \u003ccode\u003efalse\u003c/code\u003e otherwise\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eSignatures:\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003ebool \u0026lt;= bool -\u0026gt; bool\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eint \u0026lt;= int -\u0026gt; bool\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003euint \u0026lt;= uint -\u0026gt; bool\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003edouble \u0026lt;= double -\u0026gt; bool\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003estring \u0026lt;= string -\u0026gt; bool\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ebytes \u0026lt;= bytes -\u0026gt; bool\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003egoogle.protobuf.Timestamp \u0026lt;= google.protobuf.Timestamp -\u0026gt; bool\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003egoogle.protobuf.Duration \u0026lt;= google.protobuf.Duration -\u0026gt; bool\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eExamples:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"2 \u0026lt;= 3 // true\n'a' \u0026lt;= 'b' // true\ntimestamp('2023-08-25T12:00:00Z') \u0026lt;= timestamp('2023-08-26T12:00:00Z') // true\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003e2 \u0026lt;= 3 // true\n'a' \u0026lt;= 'b' // true\ntimestamp('2023-08-25T12:00:00Z') \u0026lt;= timestamp('2023-08-26T12:00:00Z') // true\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eLess Than (\u0026lt;)\u003c/strong\u003e - Compares two values and returns \u003ccode\u003etrue\u003c/code\u003e if the first value\nis less than the second value, and \u003ccode\u003efalse\u003c/code\u003e otherwise\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eSignatures:\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003ebool \u0026lt; bool -\u0026gt; bool\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eint \u0026lt; int -\u0026gt; bool\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003euint \u0026lt; uint -\u0026gt; bool\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003edouble \u0026lt; double -\u0026gt; bool\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003estring \u0026lt; string -\u0026gt; bool\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ebytes \u0026lt; bytes -\u0026gt; bool\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003egoogle.protobuf.Timestamp \u0026lt; google.protobuf.Timestamp -\u0026gt; bool\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003egoogle.protobuf.Duration \u0026lt; google.protobuf.Duration -\u0026gt; bool\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eExamples:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"2 \u0026lt; 3 // true\n'a' \u0026lt; 'b' // true\nduration('2h') \u0026lt; duration('3h') // true\n-1 \u0026lt; dyn(1u) // true\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003e2 \u0026lt; 3 // true\n'a' \u0026lt; 'b' // true\nduration('2h') \u0026lt; duration('3h') // true\n-1 \u0026lt; dyn(1u) // true\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eGreater Than or Equal To (\u0026gt;=)\u003c/strong\u003e - Compares two values and returns \u003ccode\u003etrue\u003c/code\u003e if\nthe first value is greater than or equal to the second value, and \u003ccode\u003efalse\u003c/code\u003e\notherwise\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eSignatures:\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003ebool \u0026gt;= bool -\u0026gt; bool\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eint \u0026gt;= int -\u0026gt; bool\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003euint \u0026gt;= uint -\u0026gt; bool\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003edouble \u0026gt;= double -\u0026gt; bool\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003estring \u0026gt;= string -\u0026gt; bool\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ebytes \u0026gt;= bytes -\u0026gt; bool\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003egoogle.protobuf.Timestamp \u0026gt;= google.protobuf.Timestamp -\u0026gt; bool\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003egoogle.protobuf.Duration \u0026gt;= google.protobuf.Duration -\u0026gt; bool\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eExamples:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"3 \u0026gt;= 2 // true\n'b' \u0026gt;= 'a' // true\nduration('2h') + duration('1h1m') \u0026gt;= duration('3h') // true\n1 \u0026gt;= dyn(18446744073709551615u) // false\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003e3 \u0026gt;= 2 // true\n'b' \u0026gt;= 'a' // true\nduration('2h') + duration('1h1m') \u0026gt;= duration('3h') // true\n1 \u0026gt;= dyn(18446744073709551615u) // false\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eGreater Than (\u0026gt;)\u003c/strong\u003e - Compares two values and returns \u003ccode\u003etrue\u003c/code\u003e if the first\nvalue is greater than the second value, and \u003ccode\u003efalse\u003c/code\u003e otherwise\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eSignatures:\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003ebool \u0026gt; bool -\u0026gt; bool\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eint \u0026gt; int -\u0026gt; bool\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003euint \u0026gt; uint -\u0026gt; bool\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003edouble \u0026gt; double -\u0026gt; bool\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003estring \u0026gt; string -\u0026gt; bool\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ebytes \u0026gt; bytes -\u0026gt; bool\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003egoogle.protobuf.Timestamp \u0026gt; google.protobuf.Timestamp -\u0026gt; bool\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003egoogle.protobuf.Duration \u0026gt; google.protobuf.Duration -\u0026gt; bool\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eExamples:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"3 \u0026gt; 2 // true\n'b' \u0026gt; 'a' // true\n5u \u0026gt; 3u // true\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003e3 \u0026gt; 2 // true\n'b' \u0026gt; 'a' // true\n5u \u0026gt; 3u // true\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eList Operators\u003c/h4\u003e\u003ca id=\"user-content-list-operators\" class=\"anchor\" aria-label=\"Permalink: List Operators\" href=\"#list-operators\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eList Indexing ([])\u003c/strong\u003e - list indexing. Constant time cost\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eSignatures:\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003elist(A)[int] -\u0026gt; A\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eExamples:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"[1, 2, 3][1] // 2\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003e[1, 2, 3][1] // 2\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eList Membership (in)\u003c/strong\u003e - Checks if a value is present in a list. Time cost is\nproportional to the product of the size of both arguments.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eSignatures:\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003eA in list(A) -\u0026gt; bool\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eExamples:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"2 in [1, 2, 3] // true\n\u0026quot;a\u0026quot; in [\u0026quot;b\u0026quot;, \u0026quot;c\u0026quot;] // false\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003e2 in [1, 2, 3] // true\n\"a\" in [\"b\", \"c\"] // false\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003esize\u003c/strong\u003e - Determine the number of elements in the list.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eSignatures:\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003elist.size() -\u0026gt; int\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003esize(list) -\u0026gt; int\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eExamples:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"['hello', 'world'].size() // 2\nsize(['first', 'second', 'third']) // 3\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003e['hello', 'world'].size() // 2\nsize(['first', 'second', 'third']) // 3\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eMap Operators\u003c/h4\u003e\u003ca id=\"user-content-map-operators\" class=\"anchor\" aria-label=\"Permalink: Map Operators\" href=\"#map-operators\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eMap Indexing ([])\u003c/strong\u003e - map indexing. Expected time complexity is O(1).\nSome implementations may not guarantee O(1) lookup times, please check with\nthe CEL implementation to verify. In the worst case for string keys, the\nlookup cost could be proportional to the size of the map keys times the\nsize of the index string.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eSignatures:\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003emap(A, B)[A] -\u0026gt; B\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eExamples:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"{'key1': 'value1', 'key2': 'value2'}['key1'] // 'value1'\n{'name': 'Bob', 'age': 42}['age'] // 42\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003e{'key1': 'value1', 'key2': 'value2'}['key1'] // 'value1'\n{'name': 'Bob', 'age': 42}['age'] // 42\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eMap Key Membership (in)\u003c/strong\u003e - Checks if a key exists in a map. Expected time\ncomplexity is O(1).\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eSome implementations may not guarantee O(1) lookup times, please check with\nthe CEL implementation to verify. In the worst case for string keys, the\nlookup cost could be proportional to the size of the map keys times the\nsize of the index string.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eSignatures:\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003eA in map(A, B) -\u0026gt; bool\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eExamples:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"'key1' in {'key1': 'value1', 'key2': 'value2'} // true\n3 in {1: \u0026quot;one\u0026quot;, 2: \u0026quot;two\u0026quot;} // false\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003e'key1' in {'key1': 'value1', 'key2': 'value2'} // true\n3 in {1: \"one\", 2: \"two\"} // false\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003esize\u003c/strong\u003e - Determine the number of entries in the map.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eSignatures:\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003emap.size() -\u0026gt; int\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003esize(map) -\u0026gt; int\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eExamples:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"{'hello': 'world'}.size() // 1\nsize({1: true, 2: false}) // 2\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003e{'hello': 'world'}.size() // 1\nsize({1: true, 2: false}) // 2\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eBytes Functions\u003c/h4\u003e\u003ca id=\"user-content-bytes-functions\" class=\"anchor\" aria-label=\"Permalink: Bytes Functions\" href=\"#bytes-functions\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003esize\u003c/strong\u003e - Determine the number of bytes in the sequence.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eSignatures:\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003ebytes.size() -\u0026gt; int\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003esize(bytes) -\u0026gt; int\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eExamples:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"b'hello'.size() // 5\nsize(b'world!') // 6\nsize(b'\\xF0\\x9F\\xA4\\xAA') // 4\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003eb'hello'.size() // 5\nsize(b'world!') // 6\nsize(b'\\xF0\\x9F\\xA4\\xAA') // 4\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eString Functions\u003c/h4\u003e\u003ca id=\"user-content-string-functions\" class=\"anchor\" aria-label=\"Permalink: String Functions\" href=\"#string-functions\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003econtains\u003c/strong\u003e - Tests whether the string operand contains the substring. Time\ncomplexity is proportional to the product of the sizes of the arguments.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eSignatures:\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003estring.contains(string) -\u0026gt; bool\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eExamples:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"\u0026quot;hello world\u0026quot;.contains(\u0026quot;world\u0026quot;) // true\n\u0026quot;foobar\u0026quot;.contains(\u0026quot;baz\u0026quot;) // false\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003e\"hello world\".contains(\"world\") // true\n\"foobar\".contains(\"baz\") // false\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eendsWith\u003c/strong\u003e - Tests whether the string operand ends with the specified suffix.\nAverage time complexity is linear with respect to the size of the suffix string.\nWorst-case time complexity is proportional to the product of the sizes of the\narguments.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eSignatures:\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003estring.endsWith(string) -\u0026gt; bool\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eExamples:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"\u0026quot;hello world\u0026quot;.endsWith(\u0026quot;world\u0026quot;) // true\n\u0026quot;foobar\u0026quot;.endsWith(\u0026quot;bar\u0026quot;) // true\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003e\"hello world\".endsWith(\"world\") // true\n\"foobar\".endsWith(\"bar\") // true\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003ematches\u003c/strong\u003e - Tests whether a string matches a given RE2 regular expression.\nTime complexity is proportional to the product of the sizes of the arguments\nas guaranteed by the \u003ca href=\"https://github.com/google/re2/wiki/WhyRE2\"\u003eRE2 design\u003c/a\u003e.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eSignatures:\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003ematches(string, string) -\u0026gt; bool\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003estring.matches(string) -\u0026gt; bool\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eExamples:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"matches(\u0026quot;foobar\u0026quot;, \u0026quot;foo.*\u0026quot;) // true\n\u0026quot;foobar\u0026quot;.matches(\u0026quot;foo.*\u0026quot;) // true\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003ematches(\"foobar\", \"foo.*\") // true\n\"foobar\".matches(\"foo.*\") // true\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003estartsWith\u003c/strong\u003e - Tests whether the string operand starts with the specified\nprefix. Average time complexity is linear with respect to the size of the\nprefix. Worst-case time complexity is proportional to the product of the sizes\nof the arguments.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eSignatures:\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003estring.startsWith(string) -\u0026gt; bool\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eExamples:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"\u0026quot;hello world\u0026quot;.startsWith(\u0026quot;hello\u0026quot;) // true\n\u0026quot;foobar\u0026quot;.startsWith(\u0026quot;foo\u0026quot;) // true\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003e\"hello world\".startsWith(\"hello\") // true\n\"foobar\".startsWith(\"foo\") // true\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003esize\u003c/strong\u003e - Determine the length of the string in terms of the number of Unicode\ncodepoints\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eSignatures:\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003estring.size() -\u0026gt; int\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003esize(string) -\u0026gt; int\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eExamples:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"\u0026quot;hello\u0026quot;.size() // 5\nsize(\u0026quot;world!\u0026quot;) // 6\n\u0026quot;fiance\\u0301\u0026quot;.size() // 7\nsize(string(b'\\xF0\\x9F\\xA4\\xAA')) // 1\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003e\"hello\".size() // 5\nsize(\"world!\") // 6\n\"fiance\\u0301\".size() // 7\nsize(string(b'\\xF0\\x9F\\xA4\\xAA')) // 1\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eDate/Time Functions\u003c/h4\u003e\u003ca id=\"user-content-datetime-functions\" class=\"anchor\" aria-label=\"Permalink: Date/Time Functions\" href=\"#datetime-functions\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eAll timestamp functions which take accept a timezone argument can use any of\nthe supported \u003ca href=\"https://www.joda.org/joda-time/timezones.html\" rel=\"nofollow\"\u003eJoda Timezones\u003c/a\u003e\neither using the numeric format or the geographic region.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003egetDate\u003c/strong\u003e - Get the day of the month from a timestamp (one-based indexing).\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eSignatures:\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003egoogle.protobuf.Timestamp.getDate() -\u0026gt; int\u003c/code\u003e (in UTC)\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003egoogle.protobuf.Timestamp.getDate(string) -\u0026gt; int\u003c/code\u003e (with timezone)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eExamples:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"timestamp(\u0026quot;2023-12-25T00:00:00Z\u0026quot;).getDate() // 25\ntimestamp(\u0026quot;2023-12-25T00:00:00Z\u0026quot;).getDate(\u0026quot;America/Los_Angeles\u0026quot;) // 24\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003etimestamp(\"2023-12-25T00:00:00Z\").getDate() // 25\ntimestamp(\"2023-12-25T00:00:00Z\").getDate(\"America/Los_Angeles\") // 24\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003egetDayOfMonth\u003c/strong\u003e - Get the day of the month from a timestamp (zero-based\nindexing).\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eSignatures:\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003egoogle.protobuf.Timestamp.getDayOfMonth() -\u0026gt; int\u003c/code\u003e (in UTC)\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003egoogle.protobuf.Timestamp.getDayOfMonth(string) -\u0026gt; int\u003c/code\u003e (with timezone)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eExamples:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"timestamp(\u0026quot;2023-12-25T00:00:00Z\u0026quot;).getDayOfMonth() // 24\ntimestamp(\u0026quot;2023-12-25T00:00:00Z\u0026quot;).getDayOfMonth(\u0026quot;America/Los_Angeles\u0026quot;) // 23\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003etimestamp(\"2023-12-25T00:00:00Z\").getDayOfMonth() // 24\ntimestamp(\"2023-12-25T00:00:00Z\").getDayOfMonth(\"America/Los_Angeles\") // 23\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003egetDayOfWeek\u003c/strong\u003e - Get the day of the week from a timestamp (zero-based, zero\nfor Sunday).\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eSignatures:\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003egoogle.protobuf.Timestamp.getDayOfWeek() -\u0026gt; int\u003c/code\u003e (in UTC)\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003egoogle.protobuf.Timestamp.getDayOfWeek(string) -\u0026gt; int\u003c/code\u003e (with timezone)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eExamples:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"timestamp(\u0026quot;2023-12-25T12:00:00Z\u0026quot;).getDayOfWeek() // 1 (Monday)\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003etimestamp(\"2023-12-25T12:00:00Z\").getDayOfWeek() // 1 (Monday)\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003egetDayOfYear\u003c/strong\u003e - Get the day of the year from a timestamp (zero-based\nindexing).\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eSignatures:\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003egoogle.protobuf.Timestamp.getDayOfYear() -\u0026gt; int\u003c/code\u003e (in UTC)\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003egoogle.protobuf.Timestamp.getDayOfYear(string) -\u0026gt; int\u003c/code\u003e (with timezone)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eExamples:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"timestamp(\u0026quot;2023-12-25T12:00:00Z\u0026quot;).getDayOfYear() // 358\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003etimestamp(\"2023-12-25T12:00:00Z\").getDayOfYear() // 358\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003egetFullYear\u003c/strong\u003e - Get the year from a timestamp.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eSignatures:\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003egoogle.protobuf.Timestamp.getFullYear() -\u0026gt; int\u003c/code\u003e (in UTC)\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003egoogle.protobuf.Timestamp.getFullYear(string) -\u0026gt; int\u003c/code\u003e (with timezone)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eExamples:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"timestamp(\u0026quot;2023-12-25T12:00:00Z\u0026quot;).getFullYear() // 2023\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003etimestamp(\"2023-12-25T12:00:00Z\").getFullYear() // 2023\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003egetHours\u003c/strong\u003e - Get the hour from a timestamp or convert the duration to hours\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eSignatures:\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003egoogle.protobuf.Timestamp.getHours() -\u0026gt; int\u003c/code\u003e (in UTC)\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003egoogle.protobuf.Timestamp.getHours(string) -\u0026gt; int\u003c/code\u003e (with timezone)\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003egoogle.protobuf.Duration.getHours() -\u0026gt; int\u003c/code\u003e convert the duration to hours\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eExamples:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"timestamp(\u0026quot;2023-12-25T12:00:00Z\u0026quot;).getHours() // 12\nduration(\u0026quot;3h\u0026quot;).getHours() // 3\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003etimestamp(\"2023-12-25T12:00:00Z\").getHours() // 12\nduration(\"3h\").getHours() // 3\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003egetMilliseconds\u003c/strong\u003e - Get the milliseconds from a timestamp or the\nmilliseconds portion of the duration\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eSignatures:\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003egoogle.protobuf.Timestamp.getMilliseconds() -\u0026gt; int\u003c/code\u003e obtain the\nmilliseconds component of the timestamp in UTC.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003egoogle.protobuf.Timestamp.getMilliseconds(string) -\u0026gt; int\u003c/code\u003e obtain the\nmilliseconds component with a timezone.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003egoogle.protobuf.Duration.getMilliseconds() -\u0026gt; int\u003c/code\u003e obtain the milliseconds\nportion of the duration value. Other time unit functions convert the\nduration to that format; however, this method does not.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eExamples:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"timestamp(\u0026quot;2023-12-25T12:00:00.500Z\u0026quot;).getMilliseconds() // 500\nduration(\u0026quot;1.234s\u0026quot;).getMilliseconds() // 234\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003etimestamp(\"2023-12-25T12:00:00.500Z\").getMilliseconds() // 500\nduration(\"1.234s\").getMilliseconds() // 234\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003egetMinutes\u003c/strong\u003e - Get the minutes from a timestamp or convert a duration to\nminutes\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eSignatures:\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003egoogle.protobuf.Timestamp.getMinutes() -\u0026gt; int\u003c/code\u003e get the minutes component\nof a timestamp in UTC.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003egoogle.protobuf.Timestamp.getMinutes(string) -\u0026gt; int\u003c/code\u003e get the minutes\ncomponent of a timestamp within a given timezone.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003egoogle.protobuf.Duration.getMinutes() -\u0026gt; int\u003c/code\u003e convert the duration to\nminutes.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eExamples:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"timestamp(\u0026quot;2023-12-25T12:30:00Z\u0026quot;).getMinutes() // 30\nduration(\u0026quot;1h30m\u0026quot;).getMinutes() // 90\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003etimestamp(\"2023-12-25T12:30:00Z\").getMinutes() // 30\nduration(\"1h30m\").getMinutes() // 90\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003egetMonth\u003c/strong\u003e - Get the month from a timestamp (zero-based, 0 for January).\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eSignatures:\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003egoogle.protobuf.Timestamp.getMonth() -\u0026gt; int\u003c/code\u003e (in UTC)\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003egoogle.protobuf.Timestamp.getMonth(string) -\u0026gt; int\u003c/code\u003e (with timezone)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eExamples:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"timestamp(\u0026quot;2023-12-25T12:00:00Z\u0026quot;).getMonth() // 11 (December)\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003etimestamp(\"2023-12-25T12:00:00Z\").getMonth() // 11 (December)\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003egetSeconds\u003c/strong\u003e - Get the seconds from a timestamp or convert the duration to\nseconds\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eSignatures:\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003egoogle.protobuf.Timestamp.getSeconds() -\u0026gt; int\u003c/code\u003e get the seconds component\nof the timestamp in UTC.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003egoogle.protobuf.Timestamp.getSeconds(string) -\u0026gt; int\u003c/code\u003e get the seconds\ncomponent of the timestamp with a provided timezone.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003egoogle.protobuf.Duration.getSeconds() -\u0026gt; int\u003c/code\u003e convert the duration to\nseconds.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eExamples:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"timestamp(\u0026quot;2023-12-25T12:30:30Z\u0026quot;).getSeconds() // 30\nduration(\u0026quot;1m30s\u0026quot;).getSeconds() // 90\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003etimestamp(\"2023-12-25T12:30:30Z\").getSeconds() // 30\nduration(\"1m30s\").getSeconds() // 90\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eTypes and Conversions\u003c/h4\u003e\u003ca id=\"user-content-types-and-conversions\" class=\"anchor\" aria-label=\"Permalink: Types and Conversions\" href=\"#types-and-conversions\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003ebool\u003c/strong\u003e \u003ccode\u003etype(bool)\u003c/code\u003e - Type denotation\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eSignatures:\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003ebool(bool) -\u0026gt; bool\u003c/code\u003e (identity)\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ebool(string) -\u0026gt; bool\u003c/code\u003e (type conversion)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eExamples:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"bool(true) // true\nbool(\u0026quot;true\u0026quot;) // true\nbool(\u0026quot;FALSE\u0026quot;) // false\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003ebool(true) // true\nbool(\"true\") // true\nbool(\"FALSE\") // false\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003ebytes\u003c/strong\u003e \u003ccode\u003etype(bytes)\u003c/code\u003e - Type denotation\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eSignatures:\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003ebytes(bytes) -\u0026gt; bytes\u003c/code\u003e (identity)\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ebytes(string) -\u0026gt; bytes\u003c/code\u003e (type conversion)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eExamples:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"bytes(\u0026quot;hello\u0026quot;) // b'hello'\nbytes(\u0026quot;🤪\u0026quot;) // b'\\xF0\\x9F\\xA4\\xAA'\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003ebytes(\"hello\") // b'hello'\nbytes(\"🤪\") // b'\\xF0\\x9F\\xA4\\xAA'\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003edouble\u003c/strong\u003e \u003ccode\u003etype(double)\u003c/code\u003e - Type denotation\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eSignatures:\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003edouble(double) -\u0026gt; double\u003c/code\u003e (identity)\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003edouble(int) -\u0026gt; double\u003c/code\u003e (type conversion)\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003edouble(uint) -\u0026gt; double\u003c/code\u003e (type conversion)\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003edouble(string) -\u0026gt; double\u003c/code\u003e (type conversion)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eExamples:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"double(3.14) // 3.14\ndouble(10) // 10.0\ndouble(\u0026quot;3.14\u0026quot;) // 3.14 (if successful, otherwise an error)\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003edouble(3.14) // 3.14\ndouble(10) // 10.0\ndouble(\"3.14\") // 3.14 (if successful, otherwise an error)\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eduration\u003c/strong\u003e\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eSignatures:\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003eduration(google.protobuf.Duration) -\u0026gt; google.protobuf.Duration\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eduration(string) -\u0026gt; google.protobuf.Duration\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eExamples:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"duration(\u0026quot;1h30m\u0026quot;) // google.protobuf.Duration representing 1 hour and 30 minutes\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003eduration(\"1h30m\") // google.protobuf.Duration representing 1 hour and 30 minutes\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003edyn\u003c/strong\u003e \u003ccode\u003etype(dyn)\u003c/code\u003e - Type denotation\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThe \u003ccode\u003edyn\u003c/code\u003e types does not exist at runtime, but provides a hint to the\ntype-checker to disable strong type agreement checks.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eSignatures:\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003edyn(A) -\u0026gt; dyn\u003c/code\u003e (type conversion) (where A is any type)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eExamples:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"dyn(123) // integer 123 marked `dyn` during type-checking\ndyn(\u0026quot;hello\u0026quot;) // string \u0026quot;hello\u0026quot; marked `dyn` during type-checking\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003edyn(123) // integer 123 marked `dyn` during type-checking\ndyn(\"hello\") // string \"hello\" marked `dyn` during type-checking\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eint\u003c/strong\u003e \u003ccode\u003etype(int)\u003c/code\u003e - Type denotation\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eSignatures:\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003eint(int) -\u0026gt; int\u003c/code\u003e (identity)\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eint(uint) -\u0026gt; int\u003c/code\u003e (type conversion)\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eint(double) -\u0026gt; int\u003c/code\u003e (type conversion, rounds toward zero, errors if out of\nrange)\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eint(string) -\u0026gt; int\u003c/code\u003e (type conversion)\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eint(enum E) -\u0026gt; int\u003c/code\u003e (type conversion)\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eint(google.protobuf.Timestamp) -\u0026gt; int\u003c/code\u003e converts to seconds since Unix\nepoch\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eExamples:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"int(123) // 123\nint(3.14) // 3\nint(\u0026quot;123\u0026quot;) // 123 (if successful, otherwise an error)\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003eint(123) // 123\nint(3.14) // 3\nint(\"123\") // 123 (if successful, otherwise an error)\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003elist\u003c/strong\u003e \u003ccode\u003etype(list(dyn))\u003c/code\u003e - Type denotation\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003emap\u003c/strong\u003e \u003ccode\u003etype(map(dyn, dyn))\u003c/code\u003e - Type denotation\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003enull_type\u003c/strong\u003e \u003ccode\u003etype(null)\u003c/code\u003e - Type denotation\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003estring\u003c/strong\u003e \u003ccode\u003etype(string)\u003c/code\u003e - Type denotation\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eSignatures:\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003estring(string) -\u0026gt; string\u003c/code\u003e (identity)\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003estring(bool) -\u0026gt; string\u003c/code\u003e converts \u003ccode\u003etrue\u003c/code\u003e to \u003ccode\u003e\"true\"\u003c/code\u003e and \u003ccode\u003efalse\u003c/code\u003e to\n\u003ccode\u003e\"false\"\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003estring(int) -\u0026gt; string\u003c/code\u003e converts integer values to base 10 representation\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003estring(uint) -\u0026gt; string\u003c/code\u003e converts unsigned integer values to base 10\nrepresentation\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003estring(double) -\u0026gt; string\u003c/code\u003e converts a double to a string\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003estring(bytes) -\u0026gt; string\u003c/code\u003e converts a byte sequence to a UTF-8 string, errors\nfor invalid code points\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003estring(timestamp) -\u0026gt; string\u003c/code\u003e converts a timestamp value to\n\u003ca href=\"https://datatracker.ietf.org/doc/html/rfc3339\" rel=\"nofollow\"\u003eRFC3339\u003c/a\u003e format\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003estring(duration) -\u0026gt; string\u003c/code\u003e converts a duration value to seconds and\nfractional seconds with an 's' suffix\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eExamples:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"string(123) // \u0026quot;123\u0026quot;\nstring(123u) // \u0026quot;123u\u0026quot;\nstring(3.14) // \u0026quot;3.14\u0026quot;\nstring(b'hello') // \u0026quot;hello\u0026quot;\nstring(b'\\xf0\\x9f\\xa4\\xaa') // \u0026quot;🤪\u0026quot;\nstring(duration('1m1ms')) // \u0026quot;60.001s\u0026quot;\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003estring(123) // \"123\"\nstring(123u) // \"123u\"\nstring(3.14) // \"3.14\"\nstring(b'hello') // \"hello\"\nstring(b'\\xf0\\x9f\\xa4\\xaa') // \"🤪\"\nstring(duration('1m1ms')) // \"60.001s\"\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003etimestamp\u003c/strong\u003e\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eSignatures:\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003etimestamp(google.protobuf.Timestamp) -\u0026gt; google.protobuf.Timestamp\u003c/code\u003e\n(identity)\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003etimestamp(string) -\u0026gt; google.protobuf.Timestamp\u003c/code\u003e (type conversion, according\nto RFC3339)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eExamples:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"// google.protobuf.Timestamp representing August 26, 2023 at 12:39 PM PDT\ntimestamp(\u0026quot;2023-08-26T12:39:00-07:00\u0026quot;)\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003e// google.protobuf.Timestamp representing August 26, 2023 at 12:39 PM PDT\ntimestamp(\"2023-08-26T12:39:00-07:00\")\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003etype\u003c/strong\u003e \u003ccode\u003etype\u003c/code\u003e - Type denotation\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eSignatures:\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003etype(A) -\u0026gt; type\u003c/code\u003e (returns the type of the value, where A is any type)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eExamples:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"type(123) // int\ntype(\u0026quot;hello\u0026quot;) // string\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003etype(123) // int\ntype(\"hello\") // string\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003euint\u003c/strong\u003e \u003ccode\u003etype(uint)\u003c/code\u003e - Type denotation\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eSignatures:\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003euint(uint) -\u0026gt; uint\u003c/code\u003e (identity)\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003euint(int) -\u0026gt; uint\u003c/code\u003e (type conversion)\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003euint(double) -\u0026gt; uint\u003c/code\u003e (type conversion, rounds toward zero, errors if out\nof range)\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003euint(string) -\u0026gt; uint\u003c/code\u003e (type conversion)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eExamples:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"uint(123) // 123u\nuint(3.14) // 3u\nuint(\u0026quot;123\u0026quot;) // 123u (if successful, otherwise an error)\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003euint(123) // 123u\nuint(3.14) // 3u\nuint(\"123\") // 123u (if successful, otherwise an error)\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eAppendix 1: Legacy Behavior\u003c/h2\u003e\u003ca id=\"user-content-appendix-1-legacy-behavior\" class=\"anchor\" aria-label=\"Permalink: Appendix 1: Legacy Behavior\" href=\"#appendix-1-legacy-behavior\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eHomogeneous Equality\u003c/h3\u003e\u003ca id=\"user-content-homogeneous-equality\" class=\"anchor\" aria-label=\"Permalink: Homogeneous Equality\" href=\"#homogeneous-equality\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003ePrior to cel-spec v0.7.0, CEL runtimes only supported homogeneous equality to be\nconsistent with the homogeneous equality defined by the type-checker. The\noriginal runtime definition for equality is as follows:\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"Equality and inequality are homogeneous; comparing values of different runtime\ntypes results in a runtime error. Thus `2 == 3` is `false`, but `2 == 2.0` is an\nerror.\n\nFor `double`, all not-a-number (`NaN`) values compare equal. This is different\nthan the usual semantics of floating-point numbers, but it is more consistent\nwith the usual expectations of reflexivity, and is more compatible with the\nusual notions of equality on protocol buffers.\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003eEquality and inequality are homogeneous; comparing values of different runtime\ntypes results in a runtime error. Thus `2 == 3` is `false`, but `2 == 2.0` is an\nerror.\n\nFor `double`, all not-a-number (`NaN`) values compare equal. This is different\nthan the usual semantics of floating-point numbers, but it is more consistent\nwith the usual expectations of reflexivity, and is more compatible with the\nusual notions of equality on protocol buffers.\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003c/article\u003e","renderedFileInfo":null,"shortPath":null,"symbolsEnabled":true,"tabSize":8,"topBannersInfo":{"overridingGlobalFundingFile":false,"globalPreferredFundingPath":null,"showInvalidCitationWarning":false,"citationHelpUrl":"https://docs.github.com/github/creating-cloning-and-archiving-repositories/creating-a-repository-on-github/about-citation-files","actionsOnboardingTip":null},"truncated":false,"viewable":true,"workflowRedirectUrl":null,"symbols":{"timed_out":false,"not_analyzed":false,"symbols":[{"name":"Language Definition","kind":"section_1","ident_start":2,"ident_end":21,"extent_start":0,"extent_end":81256,"fully_qualified_name":"Language Definition","ident_utf16":{"start":{"line_number":0,"utf16_col":2},"end":{"line_number":0,"utf16_col":21}},"extent_utf16":{"start":{"line_number":0,"utf16_col":0},"end":{"line_number":2208,"utf16_col":0}}},{"name":"Contents","kind":"section_2","ident_start":122,"ident_end":130,"extent_start":119,"extent_end":1688,"fully_qualified_name":"Contents","ident_utf16":{"start":{"line_number":5,"utf16_col":3},"end":{"line_number":5,"utf16_col":11}},"extent_utf16":{"start":{"line_number":5,"utf16_col":0},"end":{"line_number":46,"utf16_col":0}}},{"name":"Overview","kind":"section_2","ident_start":1691,"ident_end":1699,"extent_start":1688,"extent_end":2462,"fully_qualified_name":"Overview","ident_utf16":{"start":{"line_number":46,"utf16_col":3},"end":{"line_number":46,"utf16_col":11}},"extent_utf16":{"start":{"line_number":46,"utf16_col":0},"end":{"line_number":61,"utf16_col":0}}},{"name":"Syntax","kind":"section_2","ident_start":2465,"ident_end":2471,"extent_start":2462,"extent_end":9986,"fully_qualified_name":"Syntax","ident_utf16":{"start":{"line_number":61,"utf16_col":3},"end":{"line_number":61,"utf16_col":9}},"extent_utf16":{"start":{"line_number":61,"utf16_col":0},"end":{"line_number":223,"utf16_col":0}}},{"name":"Name Resolution","kind":"section_3","ident_start":8189,"ident_end":8204,"extent_start":8185,"extent_end":9986,"fully_qualified_name":"Name Resolution","ident_utf16":{"start":{"line_number":191,"utf16_col":4},"end":{"line_number":191,"utf16_col":19}},"extent_utf16":{"start":{"line_number":191,"utf16_col":0},"end":{"line_number":223,"utf16_col":0}}},{"name":"Values","kind":"section_2","ident_start":9989,"ident_end":9995,"extent_start":9986,"extent_end":24232,"fully_qualified_name":"Values","ident_utf16":{"start":{"line_number":223,"utf16_col":3},"end":{"line_number":223,"utf16_col":9}},"extent_utf16":{"start":{"line_number":223,"utf16_col":0},"end":{"line_number":517,"utf16_col":0}}},{"name":"Numeric Values","kind":"section_3","ident_start":10663,"ident_end":10677,"extent_start":10659,"extent_end":11934,"fully_qualified_name":"Numeric Values","ident_utf16":{"start":{"line_number":241,"utf16_col":4},"end":{"line_number":241,"utf16_col":18}},"extent_utf16":{"start":{"line_number":241,"utf16_col":0},"end":{"line_number":264,"utf16_col":0}}},{"name":"String and Bytes Values","kind":"section_3","ident_start":11938,"ident_end":11961,"extent_start":11934,"extent_end":16118,"fully_qualified_name":"String and Bytes Values","ident_utf16":{"start":{"line_number":264,"utf16_col":4},"end":{"line_number":264,"utf16_col":27}},"extent_utf16":{"start":{"line_number":264,"utf16_col":0},"end":{"line_number":357,"utf16_col":0}}},{"name":"Aggregate Values","kind":"section_3","ident_start":16122,"ident_end":16138,"extent_start":16118,"extent_end":17680,"fully_qualified_name":"Aggregate Values","ident_utf16":{"start":{"line_number":357,"utf16_col":4},"end":{"line_number":357,"utf16_col":20}},"extent_utf16":{"start":{"line_number":357,"utf16_col":0},"end":{"line_number":388,"utf16_col":0}}},{"name":"Booleans and Null","kind":"section_3","ident_start":17684,"ident_end":17701,"extent_start":17680,"extent_end":18070,"fully_qualified_name":"Booleans and Null","ident_utf16":{"start":{"line_number":388,"utf16_col":4},"end":{"line_number":388,"utf16_col":21}},"extent_utf16":{"start":{"line_number":388,"utf16_col":0},"end":{"line_number":398,"utf16_col":0}}},{"name":"Type Values","kind":"section_3","ident_start":18074,"ident_end":18085,"extent_start":18070,"extent_end":18558,"fully_qualified_name":"Type Values","ident_utf16":{"start":{"line_number":398,"utf16_col":4},"end":{"line_number":398,"utf16_col":15}},"extent_utf16":{"start":{"line_number":398,"utf16_col":0},"end":{"line_number":412,"utf16_col":0}}},{"name":"Abstract Types","kind":"section_3","ident_start":18562,"ident_end":18576,"extent_start":18558,"extent_end":19631,"fully_qualified_name":"Abstract Types","ident_utf16":{"start":{"line_number":412,"utf16_col":4},"end":{"line_number":412,"utf16_col":18}},"extent_utf16":{"start":{"line_number":412,"utf16_col":0},"end":{"line_number":431,"utf16_col":0}}},{"name":"Protocol Buffer Data Conversion","kind":"section_3","ident_start":19635,"ident_end":19666,"extent_start":19631,"extent_end":22806,"fully_qualified_name":"Protocol Buffer Data Conversion","ident_utf16":{"start":{"line_number":431,"utf16_col":4},"end":{"line_number":431,"utf16_col":35}},"extent_utf16":{"start":{"line_number":431,"utf16_col":0},"end":{"line_number":489,"utf16_col":0}}},{"name":"Dynamic Values","kind":"section_3","ident_start":22810,"ident_end":22824,"extent_start":22806,"extent_end":24232,"fully_qualified_name":"Dynamic Values","ident_utf16":{"start":{"line_number":489,"utf16_col":4},"end":{"line_number":489,"utf16_col":18}},"extent_utf16":{"start":{"line_number":489,"utf16_col":0},"end":{"line_number":517,"utf16_col":0}}},{"name":"JSON Data Conversion","kind":"section_2","ident_start":24235,"ident_end":24255,"extent_start":24232,"extent_end":26217,"fully_qualified_name":"JSON Data Conversion","ident_utf16":{"start":{"line_number":517,"utf16_col":3},"end":{"line_number":517,"utf16_col":23}},"extent_utf16":{"start":{"line_number":517,"utf16_col":0},"end":{"line_number":553,"utf16_col":0}}},{"name":"Gradual Type Checking","kind":"section_2","ident_start":26220,"ident_end":26241,"extent_start":26217,"extent_end":28761,"fully_qualified_name":"Gradual Type Checking","ident_utf16":{"start":{"line_number":553,"utf16_col":3},"end":{"line_number":553,"utf16_col":24}},"extent_utf16":{"start":{"line_number":553,"utf16_col":0},"end":{"line_number":598,"utf16_col":0}}},{"name":"Evaluation","kind":"section_2","ident_start":28764,"ident_end":28774,"extent_start":28761,"extent_end":39025,"fully_qualified_name":"Evaluation","ident_utf16":{"start":{"line_number":598,"utf16_col":3},"end":{"line_number":598,"utf16_col":13}},"extent_utf16":{"start":{"line_number":598,"utf16_col":0},"end":{"line_number":783,"utf16_col":0}}},{"name":"Evaluation Environment","kind":"section_3","ident_start":30562,"ident_end":30584,"extent_start":30558,"extent_end":32252,"fully_qualified_name":"Evaluation Environment","ident_utf16":{"start":{"line_number":631,"utf16_col":4},"end":{"line_number":631,"utf16_col":26}},"extent_utf16":{"start":{"line_number":631,"utf16_col":0},"end":{"line_number":661,"utf16_col":0}}},{"name":"Runtime Errors","kind":"section_3","ident_start":32256,"ident_end":32270,"extent_start":32252,"extent_end":32880,"fully_qualified_name":"Runtime Errors","ident_utf16":{"start":{"line_number":661,"utf16_col":4},"end":{"line_number":661,"utf16_col":18}},"extent_utf16":{"start":{"line_number":661,"utf16_col":0},"end":{"line_number":677,"utf16_col":0}}},{"name":"Logical Operators","kind":"section_3","ident_start":32884,"ident_end":32901,"extent_start":32880,"extent_end":33879,"fully_qualified_name":"Logical Operators","ident_utf16":{"start":{"line_number":677,"utf16_col":4},"end":{"line_number":677,"utf16_col":21}},"extent_utf16":{"start":{"line_number":677,"utf16_col":0},"end":{"line_number":696,"utf16_col":0}}},{"name":"Macros","kind":"section_3","ident_start":33883,"ident_end":33889,"extent_start":33879,"extent_end":36839,"fully_qualified_name":"Macros","ident_utf16":{"start":{"line_number":696,"utf16_col":4},"end":{"line_number":696,"utf16_col":10}},"extent_utf16":{"start":{"line_number":696,"utf16_col":0},"end":{"line_number":741,"utf16_col":0}}},{"name":"Field Selection","kind":"section_3","ident_start":36843,"ident_end":36858,"extent_start":36839,"extent_end":39025,"fully_qualified_name":"Field Selection","ident_utf16":{"start":{"line_number":741,"utf16_col":4},"end":{"line_number":741,"utf16_col":19}},"extent_utf16":{"start":{"line_number":741,"utf16_col":0},"end":{"line_number":783,"utf16_col":0}}},{"name":"Performance","kind":"section_2","ident_start":39028,"ident_end":39039,"extent_start":39025,"extent_end":45682,"fully_qualified_name":"Performance","ident_utf16":{"start":{"line_number":783,"utf16_col":3},"end":{"line_number":783,"utf16_col":14}},"extent_utf16":{"start":{"line_number":783,"utf16_col":0},"end":{"line_number":944,"utf16_col":0}}},{"name":"Abstract Sizes","kind":"section_3","ident_start":39614,"ident_end":39628,"extent_start":39610,"extent_end":40799,"fully_qualified_name":"Abstract Sizes","ident_utf16":{"start":{"line_number":795,"utf16_col":4},"end":{"line_number":795,"utf16_col":18}},"extent_utf16":{"start":{"line_number":795,"utf16_col":0},"end":{"line_number":823,"utf16_col":0}}},{"name":"Time Complexity","kind":"section_3","ident_start":40803,"ident_end":40818,"extent_start":40799,"extent_end":42335,"fully_qualified_name":"Time Complexity","ident_utf16":{"start":{"line_number":823,"utf16_col":4},"end":{"line_number":823,"utf16_col":19}},"extent_utf16":{"start":{"line_number":823,"utf16_col":0},"end":{"line_number":861,"utf16_col":0}}},{"name":"Space Complexity","kind":"section_3","ident_start":42339,"ident_end":42355,"extent_start":42335,"extent_end":42851,"fully_qualified_name":"Space Complexity","ident_utf16":{"start":{"line_number":861,"utf16_col":4},"end":{"line_number":861,"utf16_col":20}},"extent_utf16":{"start":{"line_number":861,"utf16_col":0},"end":{"line_number":876,"utf16_col":0}}},{"name":"Macro Performance","kind":"section_3","ident_start":42855,"ident_end":42872,"extent_start":42851,"extent_end":43980,"fully_qualified_name":"Macro Performance","ident_utf16":{"start":{"line_number":876,"utf16_col":4},"end":{"line_number":876,"utf16_col":21}},"extent_utf16":{"start":{"line_number":876,"utf16_col":0},"end":{"line_number":913,"utf16_col":0}}},{"name":"Performance Limits","kind":"section_3","ident_start":43984,"ident_end":44002,"extent_start":43980,"extent_end":45682,"fully_qualified_name":"Performance Limits","ident_utf16":{"start":{"line_number":913,"utf16_col":4},"end":{"line_number":913,"utf16_col":22}},"extent_utf16":{"start":{"line_number":913,"utf16_col":0},"end":{"line_number":944,"utf16_col":0}}},{"name":"Functions","kind":"section_2","ident_start":45685,"ident_end":45694,"extent_start":45682,"extent_end":48559,"fully_qualified_name":"Functions","ident_utf16":{"start":{"line_number":944,"utf16_col":3},"end":{"line_number":944,"utf16_col":12}},"extent_utf16":{"start":{"line_number":944,"utf16_col":0},"end":{"line_number":1030,"utf16_col":0}}},{"name":"Extension Functions","kind":"section_3","ident_start":47632,"ident_end":47651,"extent_start":47628,"extent_end":48310,"fully_qualified_name":"Extension Functions","ident_utf16":{"start":{"line_number":1011,"utf16_col":4},"end":{"line_number":1011,"utf16_col":23}},"extent_utf16":{"start":{"line_number":1011,"utf16_col":0},"end":{"line_number":1024,"utf16_col":0}}},{"name":"Receiver Call Style","kind":"section_3","ident_start":48314,"ident_end":48333,"extent_start":48310,"extent_end":48559,"fully_qualified_name":"Receiver Call Style","ident_utf16":{"start":{"line_number":1024,"utf16_col":4},"end":{"line_number":1024,"utf16_col":23}},"extent_utf16":{"start":{"line_number":1024,"utf16_col":0},"end":{"line_number":1030,"utf16_col":0}}},{"name":"Standard Definitions","kind":"section_2","ident_start":48562,"ident_end":48582,"extent_start":48559,"extent_end":80530,"fully_qualified_name":"Standard Definitions","ident_utf16":{"start":{"line_number":1030,"utf16_col":3},"end":{"line_number":1030,"utf16_col":23}},"extent_utf16":{"start":{"line_number":1030,"utf16_col":0},"end":{"line_number":2190,"utf16_col":0}}},{"name":"Equality","kind":"section_3","ident_start":48810,"ident_end":48818,"extent_start":48806,"extent_end":54540,"fully_qualified_name":"Equality","ident_utf16":{"start":{"line_number":1036,"utf16_col":4},"end":{"line_number":1036,"utf16_col":12}},"extent_utf16":{"start":{"line_number":1036,"utf16_col":0},"end":{"line_number":1174,"utf16_col":0}}},{"name":"Numbers","kind":"section_4","ident_start":50307,"ident_end":50314,"extent_start":50302,"extent_end":51331,"fully_qualified_name":"Numbers","ident_utf16":{"start":{"line_number":1069,"utf16_col":5},"end":{"line_number":1069,"utf16_col":12}},"extent_utf16":{"start":{"line_number":1069,"utf16_col":0},"end":{"line_number":1099,"utf16_col":0}}},{"name":"Lists and Maps","kind":"section_4","ident_start":51336,"ident_end":51350,"extent_start":51331,"extent_end":51890,"fully_qualified_name":"Lists and Maps","ident_utf16":{"start":{"line_number":1099,"utf16_col":5},"end":{"line_number":1099,"utf16_col":19}},"extent_utf16":{"start":{"line_number":1099,"utf16_col":0},"end":{"line_number":1118,"utf16_col":0}}},{"name":"Protocol Buffers","kind":"section_4","ident_start":51895,"ident_end":51911,"extent_start":51890,"extent_end":54540,"fully_qualified_name":"Protocol Buffers","ident_utf16":{"start":{"line_number":1118,"utf16_col":5},"end":{"line_number":1118,"utf16_col":21}},"extent_utf16":{"start":{"line_number":1118,"utf16_col":0},"end":{"line_number":1174,"utf16_col":0}}},{"name":"Ordering","kind":"section_3","ident_start":54544,"ident_end":54552,"extent_start":54540,"extent_end":55165,"fully_qualified_name":"Ordering","ident_utf16":{"start":{"line_number":1174,"utf16_col":4},"end":{"line_number":1174,"utf16_col":12}},"extent_utf16":{"start":{"line_number":1174,"utf16_col":0},"end":{"line_number":1188,"utf16_col":0}}},{"name":"Overflow","kind":"section_3","ident_start":55169,"ident_end":55177,"extent_start":55165,"extent_end":56033,"fully_qualified_name":"Overflow","ident_utf16":{"start":{"line_number":1188,"utf16_col":4},"end":{"line_number":1188,"utf16_col":12}},"extent_utf16":{"start":{"line_number":1188,"utf16_col":0},"end":{"line_number":1206,"utf16_col":0}}},{"name":"Timezones","kind":"section_3","ident_start":56037,"ident_end":56046,"extent_start":56033,"extent_end":56462,"fully_qualified_name":"Timezones","ident_utf16":{"start":{"line_number":1206,"utf16_col":4},"end":{"line_number":1206,"utf16_col":13}},"extent_utf16":{"start":{"line_number":1206,"utf16_col":0},"end":{"line_number":1221,"utf16_col":0}}},{"name":"Regular Expressions","kind":"section_3","ident_start":56466,"ident_end":56485,"extent_start":56462,"extent_end":56747,"fully_qualified_name":"Regular Expressions","ident_utf16":{"start":{"line_number":1221,"utf16_col":4},"end":{"line_number":1221,"utf16_col":23}},"extent_utf16":{"start":{"line_number":1221,"utf16_col":0},"end":{"line_number":1228,"utf16_col":0}}},{"name":"Standard Environment","kind":"section_3","ident_start":56751,"ident_end":56771,"extent_start":56747,"extent_end":80530,"fully_qualified_name":"Standard Environment","ident_utf16":{"start":{"line_number":1228,"utf16_col":4},"end":{"line_number":1228,"utf16_col":24}},"extent_utf16":{"start":{"line_number":1228,"utf16_col":0},"end":{"line_number":2190,"utf16_col":0}}},{"name":"Presence and Comprehension Macros","kind":"section_4","ident_start":56778,"ident_end":56811,"extent_start":56773,"extent_end":60573,"fully_qualified_name":"Presence and Comprehension Macros","ident_utf16":{"start":{"line_number":1230,"utf16_col":5},"end":{"line_number":1230,"utf16_col":38}},"extent_utf16":{"start":{"line_number":1230,"utf16_col":0},"end":{"line_number":1352,"utf16_col":0}}},{"name":"Logical Operators","kind":"section_4","ident_start":60578,"ident_end":60595,"extent_start":60573,"extent_end":62165,"fully_qualified_name":"Logical Operators","ident_utf16":{"start":{"line_number":1352,"utf16_col":5},"end":{"line_number":1352,"utf16_col":22}},"extent_utf16":{"start":{"line_number":1352,"utf16_col":0},"end":{"line_number":1428,"utf16_col":0}}},{"name":"Arithmetic Operators","kind":"section_4","ident_start":62170,"ident_end":62190,"extent_start":62165,"extent_end":64315,"fully_qualified_name":"Arithmetic Operators","ident_utf16":{"start":{"line_number":1428,"utf16_col":5},"end":{"line_number":1428,"utf16_col":25}},"extent_utf16":{"start":{"line_number":1428,"utf16_col":0},"end":{"line_number":1520,"utf16_col":0}}},{"name":"Comparison Operators","kind":"section_4","ident_start":64320,"ident_end":64340,"extent_start":64315,"extent_end":68006,"fully_qualified_name":"Comparison Operators","ident_utf16":{"start":{"line_number":1520,"utf16_col":5},"end":{"line_number":1520,"utf16_col":25}},"extent_utf16":{"start":{"line_number":1520,"utf16_col":0},"end":{"line_number":1656,"utf16_col":0}}},{"name":"List Operators","kind":"section_4","ident_start":68011,"ident_end":68025,"extent_start":68006,"extent_end":68655,"fully_qualified_name":"List Operators","ident_utf16":{"start":{"line_number":1656,"utf16_col":5},"end":{"line_number":1656,"utf16_col":19}},"extent_utf16":{"start":{"line_number":1656,"utf16_col":0},"end":{"line_number":1698,"utf16_col":0}}},{"name":"Map Operators","kind":"section_4","ident_start":68660,"ident_end":68673,"extent_start":68655,"extent_end":69877,"fully_qualified_name":"Map Operators","ident_utf16":{"start":{"line_number":1698,"utf16_col":5},"end":{"line_number":1698,"utf16_col":18}},"extent_utf16":{"start":{"line_number":1698,"utf16_col":0},"end":{"line_number":1750,"utf16_col":0}}},{"name":"Bytes Functions","kind":"section_4","ident_start":69882,"ident_end":69897,"extent_start":69877,"extent_end":70125,"fully_qualified_name":"Bytes Functions","ident_utf16":{"start":{"line_number":1750,"utf16_col":5},"end":{"line_number":1750,"utf16_col":20}},"extent_utf16":{"start":{"line_number":1750,"utf16_col":0},"end":{"line_number":1767,"utf16_col":0}}},{"name":"String Functions","kind":"section_4","ident_start":70130,"ident_end":70146,"extent_start":70125,"extent_end":71981,"fully_qualified_name":"String Functions","ident_utf16":{"start":{"line_number":1767,"utf16_col":5},"end":{"line_number":1767,"utf16_col":21}},"extent_utf16":{"start":{"line_number":1767,"utf16_col":0},"end":{"line_number":1848,"utf16_col":0}}},{"name":"Date/Time Functions","kind":"section_4","ident_start":71986,"ident_end":72005,"extent_start":71981,"extent_end":76456,"fully_qualified_name":"Date/Time Functions","ident_utf16":{"start":{"line_number":1848,"utf16_col":5},"end":{"line_number":1848,"utf16_col":24}},"extent_utf16":{"start":{"line_number":1848,"utf16_col":0},"end":{"line_number":2010,"utf16_col":0}}},{"name":"Types and Conversions","kind":"section_4","ident_start":76461,"ident_end":76482,"extent_start":76456,"extent_end":80530,"fully_qualified_name":"Types and Conversions","ident_utf16":{"start":{"line_number":2010,"utf16_col":5},"end":{"line_number":2010,"utf16_col":26}},"extent_utf16":{"start":{"line_number":2010,"utf16_col":0},"end":{"line_number":2190,"utf16_col":0}}},{"name":"Appendix 1: Legacy Behavior","kind":"section_2","ident_start":80533,"ident_end":80560,"extent_start":80530,"extent_end":81256,"fully_qualified_name":"Appendix 1: Legacy Behavior","ident_utf16":{"start":{"line_number":2190,"utf16_col":3},"end":{"line_number":2190,"utf16_col":30}},"extent_utf16":{"start":{"line_number":2190,"utf16_col":0},"end":{"line_number":2208,"utf16_col":0}}},{"name":"Homogeneous Equality","kind":"section_3","ident_start":80566,"ident_end":80586,"extent_start":80562,"extent_end":81256,"fully_qualified_name":"Homogeneous Equality","ident_utf16":{"start":{"line_number":2192,"utf16_col":4},"end":{"line_number":2192,"utf16_col":24}},"extent_utf16":{"start":{"line_number":2192,"utf16_col":0},"end":{"line_number":2208,"utf16_col":0}}}]}},"copilotInfo":null,"copilotAccessAllowed":false,"modelsAccessAllowed":false,"csrf_tokens":{"/google/cel-spec/branches":{"post":"mSt_jGpM990udD-KCAc8HzNRSzjMPZi6ISyVscKXtHcD2ZgVMrE8yBFLGztLGeCz_RNHp2oMmvxcS7sFOyZbZA"},"/repos/preferences":{"post":"Jj-ADcbZ9TDYatoLKstuZRDSO1p91BgVIPOtXeMhyabj_mxaYLIghwfnBeb4rdkpTgrxEtwfXgrZLZISoQ1y_w"}}},"title":"cel-spec/doc/langdef.md at master · google/cel-spec","appPayload":{"helpUrl":"https://docs.github.com","findFileWorkerPath":"/assets-cdn/worker/find-file-worker-9f8a877aa99f.js","findInFileWorkerPath":"/assets-cdn/worker/find-in-file-worker-96e76d5fdb2c.js","githubDevUrl":null,"enabled_features":{"code_nav_ui_events":false,"overview_shared_code_dropdown_button":false,"react_blob_overlay":false,"copilot_conversational_ux_embedding_update":false,"copilot_smell_icebreaker_ux":true,"accessible_code_button":true}}}</script> <div data-target="react-app.reactRoot"><style data-styled="true" data-styled-version="5.3.11">.hOfjFo{padding:0;}/*!sc*/ .oDGAe{max-width:100%;margin-left:auto;margin-right:auto;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;}/*!sc*/ .kowOcT{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex:1 1 100%;-ms-flex:1 1 100%;flex:1 1 100%;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;max-width:100%;}/*!sc*/ .gISSDQ{width:100%;}/*!sc*/ @media screen and (min-width:544px){.gISSDQ{width:100%;}}/*!sc*/ @media screen and (min-width:768px){.gISSDQ{width:auto;}}/*!sc*/ .cEmWSE{display:none;-webkit-order:1;-ms-flex-order:1;order:1;width:100%;margin-left:0;margin-right:0;-webkit-flex-direction:column-reverse;-ms-flex-direction:column-reverse;flex-direction:column-reverse;margin-bottom:0;min-width:0;}/*!sc*/ @media screen and (min-width:768px){.cEmWSE{width:auto;margin-top:0 !important;margin-bottom:0 !important;position:-webkit-sticky;position:sticky;top:0px;max-height:100vh !important;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;margin-right:0;height:100vh;}}/*!sc*/ @media print,screen and (max-width:1011px) and (min-width:768px){.cEmWSE{display:none;}}/*!sc*/ .hPvFuC{margin-left:0;margin-right:0;display:none;margin-top:0;}/*!sc*/ @media screen and (min-width:768px){.hPvFuC{margin-left:0 !important;margin-right:0 !important;}}/*!sc*/ .fFSoPl{--pane-min-width:256px;--pane-max-width-diff:511px;--pane-max-width:calc(100vw - var(--pane-max-width-diff));width:100%;padding:0;}/*!sc*/ @media screen and (min-width:544px){}/*!sc*/ @media screen and (min-width:768px){.fFSoPl{width:clamp(var(--pane-min-width),var(--pane-width),var(--pane-max-width));overflow:auto;}}/*!sc*/ @media screen and (min-width:1280px){.fFSoPl{--pane-max-width-diff:959px;}}/*!sc*/ .bTBnTW{height:100%;position:relative;display:none;margin-left:0;}/*!sc*/ .bHLmSv{position:absolute;inset:0 -2px;cursor:col-resize;background-color:transparent;-webkit-transition-delay:0.1s;transition-delay:0.1s;}/*!sc*/ .bHLmSv:hover{background-color:var(--bgColor-neutral-muted,var(--color-neutral-muted,rgba(175,184,193,0.2)));}/*!sc*/ .iKqMNA{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;-webkit-order:2;-ms-flex-order:2;order:2;-webkit-flex-basis:0;-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;-webkit-flex-shrink:1;-ms-flex-negative:1;flex-shrink:1;min-width:1px;margin-right:auto;}/*!sc*/ @media print{.iKqMNA{display:-webkit-box !important;display:-webkit-flex !important;display:-ms-flexbox !important;display:flex !important;}}/*!sc*/ .FxAyp{width:100%;max-width:100%;margin-left:auto;margin-right:auto;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;padding:0;}/*!sc*/ .leYMvG{margin-left:auto;margin-right:auto;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding-bottom:40px;max-width:100%;margin-top:0;}/*!sc*/ .KMPzq{display:inherit;}/*!sc*/ .hfKjHv{width:100%;}/*!sc*/ .gZWyZE{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;width:100%;}/*!sc*/ .dwYKDk{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:start;-webkit-box-align:start;-ms-flex-align:start;align-items:start;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;gap:8px;}/*!sc*/ .ibcGmb{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:start;-webkit-box-align:start;-ms-flex-align:start;align-items:start;min-width:0;}/*!sc*/ .hKaEJF{display:block;margin-right:8px;}/*!sc*/ @media screen and (min-width:1360px){.hKaEJF{display:block;}}/*!sc*/ .XosP{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;font-size:14px;}/*!sc*/ .bCKfWo[data-size="medium"]{color:var(--fgColor-muted,var(--color-fg-muted,#656d76));padding-left:8px;padding-right:8px;display:none;}/*!sc*/ @media screen and (max-width:768px){.bCKfWo[data-size="medium"]{display:block;}}/*!sc*/ .gUkoLg{-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;}/*!sc*/ .dmxRgG[data-size="medium"]{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;}/*!sc*/ .dmxRgG[data-size="medium"] svg{color:var(--fgColor-muted,var(--color-fg-muted,#656d76));}/*!sc*/ .dmxRgG[data-size="medium"] > span{width:inherit;}/*!sc*/ .bZBlpz{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;width:100%;}/*!sc*/ .lhTYNA{margin-right:4px;color:var(--fgColor-muted,var(--color-fg-muted,#656d76));}/*!sc*/ .dbrgmi{font-size:14px;min-width:0;max-width:125px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}/*!sc*/ .dHJiml{-webkit-align-self:center;-ms-flex-item-align:center;align-self:center;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;padding-left:8px;padding-right:8px;min-width:0;}/*!sc*/ .cEytCf{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;font-size:16px;min-width:0;-webkit-flex-shrink:1;-ms-flex-negative:1;flex-shrink:1;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;max-width:100%;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;}/*!sc*/ .fzFXnm{max-width:100%;}/*!sc*/ .iMnkmv{max-width:100%;list-style:none;display:inline-block;}/*!sc*/ .ghzDag{display:inline-block;max-width:100%;}/*!sc*/ .kHuKdh{font-weight:600;}/*!sc*/ .kgiVEz{font-weight:400;}/*!sc*/ .jGhzSQ{font-weight:600;display:inline-block;max-width:100%;font-size:16px;}/*!sc*/ .faNtbn{min-height:32px;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:start;-webkit-box-align:start;-ms-flex-align:start;align-items:start;}/*!sc*/ .fmQaBv{margin-left:4px;margin-right:4px;}/*!sc*/ .dwNhzn[data-size="medium"][data-no-visuals]{border-top-left-radius:0;border-bottom-left-radius:0;display:none;}/*!sc*/ .fGwBZA[data-size="medium"][data-no-visuals]{color:var(--fgColor-muted,var(--color-fg-muted,#656d76));}/*!sc*/ .dJxjrT{margin-left:16px;margin-right:16px;}/*!sc*/ .eFxKDQ{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;}/*!sc*/ .dzCJzi{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;gap:8px;min-width:273px;padding:8px;}/*!sc*/ @media screen and (min-width:544px){.dzCJzi{-webkit-flex-wrap:nowrap;-ms-flex-wrap:nowrap;flex-wrap:nowrap;}}/*!sc*/ .ldRxiI{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;}/*!sc*/ .fVkfyA{width:100%;height:-webkit-fit-content;height:-moz-fit-content;height:fit-content;min-width:0;margin-right:0;}/*!sc*/ .gNAmSV{height:40px;padding-left:4px;padding-bottom:16px;}/*!sc*/ .jNEwzY{-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;}/*!sc*/ .bsDwxw{font-size:12px;-webkit-flex:auto;-ms-flex:auto;flex:auto;padding-right:16px;color:var(--fgColor-muted,var(--color-fg-muted,#656d76));min-width:0;}/*!sc*/ .jdLMhu{top:0px;z-index:4;background:var(--bgColor-default,var(--color-canvas-default));position:-webkit-sticky;position:sticky;}/*!sc*/ .tOISc{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;width:100%;position:absolute;}/*!sc*/ .hqwSEx{display:none;min-width:0;padding-top:8px;padding-bottom:8px;}/*!sc*/ .bDVoEr{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;overflow:hidden;margin-left:8px;margin-right:8px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;width:100%;}/*!sc*/ .kYLlPM{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;}/*!sc*/ .gYjEmn{margin-left:4px;margin-right:8px;}/*!sc*/ .kGqOLL{text-overflow:ellipsis;overflow:hidden;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;}/*!sc*/ .fHind{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;font-size:14px;min-width:0;-webkit-flex-shrink:1;-ms-flex-negative:1;flex-shrink:1;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;max-width:100%;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;}/*!sc*/ .dnZoUW{font-weight:600;display:inline-block;max-width:100%;font-size:14px;}/*!sc*/ .jRZWlf[data-size="small"]{color:var(--fgColor-default,var(--color-fg-default,#1F2328));margin-left:8px;}/*!sc*/ .kTvpNk{padding-left:8px;padding-top:8px;padding-bottom:8px;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex:1;-ms-flex:1;flex:1;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;background-color:var(--bgColor-muted,var(--color-canvas-subtle,#f6f8fa));border:1px solid var(--borderColor-default,var(--color-border-default));border-radius:6px 6px 0px 0px;}/*!sc*/ .iNMjfP{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;gap:8px;min-width:0;}/*!sc*/ .fefCSX{display:block;position:relative;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;margin-top:-1px;margin-bottom:-1px;--separator-color:transparent;}/*!sc*/ .fefCSX:not(:last-child){margin-right:1px;}/*!sc*/ .fefCSX:not(:last-child):after{background-color:var(--separator-color);content:"";position:absolute;right:-2px;top:8px;bottom:8px;width:1px;}/*!sc*/ .fefCSX:focus-within:has(:focus-visible){--separator-color:transparent;}/*!sc*/ .fefCSX:first-child{margin-left:-1px;}/*!sc*/ .fefCSX:last-child{margin-right:-1px;}/*!sc*/ .idgUkN{display:block;position:relative;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;margin-top:-1px;margin-bottom:-1px;--separator-color:var(--borderColor-default,var(--color-border-default,#d0d7de));}/*!sc*/ .idgUkN:not(:last-child){margin-right:1px;}/*!sc*/ .idgUkN:not(:last-child):after{background-color:var(--separator-color);content:"";position:absolute;right:-2px;top:8px;bottom:8px;width:1px;}/*!sc*/ .idgUkN:focus-within:has(:focus-visible){--separator-color:transparent;}/*!sc*/ .idgUkN:first-child{margin-left:-1px;}/*!sc*/ .idgUkN:last-child{margin-right:-1px;}/*!sc*/ .kcLCKF{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;gap:8px;margin-right:8px;}/*!sc*/ .kVWtTz{gap:8px;}/*!sc*/ .gWqxTd{padding-left:8px;padding-right:8px;}/*!sc*/ .gWqxTd linkButtonSx:hover:not([disabled]){-webkit-text-decoration:none;text-decoration:none;}/*!sc*/ .gWqxTd linkButtonSx:focus:not([disabled]){-webkit-text-decoration:none;text-decoration:none;}/*!sc*/ .gWqxTd linkButtonSx:active:not([disabled]){-webkit-text-decoration:none;text-decoration:none;}/*!sc*/ .ivobqY[data-size="small"][data-no-visuals]{border-top-left-radius:0;border-bottom-left-radius:0;}/*!sc*/ .iNRSob[data-size="small"][data-no-visuals]{color:var(--fgColor-muted,var(--color-fg-muted));margin-right:8px;}/*!sc*/ .ffkqe[data-size="small"][data-no-visuals]{color:var(--fgColor-muted,var(--color-fg-muted,#656d76));}/*!sc*/ .hGyMdv{border:1px solid;border-top:none;border-color:var(--borderColor-default,var(--color-border-default,#d0d7de));border-radius:0px 0px 6px 6px;min-width:273px;}/*!sc*/ .fGqKFv{background-color:var(--bgColor-default,var(--color-canvas-default));border:0px;border-width:0;border-radius:0px 0px 6px 6px;padding:0;min-width:0;margin-top:46px;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;}/*!sc*/ .eoaCFS{border-bottom-left-radius:6px;border-bottom-right-radius:6px;padding:32px;min-width:0;}/*!sc*/ .cCoXib{position:fixed;top:0;right:0;height:100%;width:15px;-webkit-transition:-webkit-transform 0.3s;-webkit-transition:transform 0.3s;transition:transform 0.3s;z-index:1;}/*!sc*/ .cCoXib:hover{-webkit-transform:scaleX(1.5);-ms-transform:scaleX(1.5);transform:scaleX(1.5);}/*!sc*/ data-styled.g1[id="Box-sc-g0xbh4-0"]{content:"hOfjFo,oDGAe,kowOcT,gISSDQ,cEmWSE,hPvFuC,fFSoPl,bTBnTW,bHLmSv,iKqMNA,FxAyp,leYMvG,KMPzq,hfKjHv,gZWyZE,dwYKDk,ibcGmb,hKaEJF,XosP,bCKfWo,gUkoLg,dmxRgG,bZBlpz,lhTYNA,dbrgmi,dHJiml,cEytCf,fzFXnm,iMnkmv,ghzDag,kHuKdh,kgiVEz,jGhzSQ,faNtbn,fmQaBv,dwNhzn,fGwBZA,dJxjrT,eFxKDQ,dzCJzi,ldRxiI,fVkfyA,gNAmSV,jNEwzY,bsDwxw,jdLMhu,tOISc,hqwSEx,bDVoEr,kYLlPM,gYjEmn,kGqOLL,fHind,dnZoUW,jRZWlf,kTvpNk,iNMjfP,fefCSX,idgUkN,kcLCKF,kVWtTz,gWqxTd,ivobqY,iNRSob,ffkqe,hGyMdv,fGqKFv,eoaCFS,cCoXib,"}/*!sc*/ .eMMFM{min-width:0;}/*!sc*/ .eMMFM:where([data-size='small']){font-size:var(--text-body-size-small,0.75rem);line-height:var(--text-body-lineHeight-small,1.6666);}/*!sc*/ .eMMFM:where([data-size='medium']){font-size:var(--text-body-size-medium,0.875rem);line-height:var(--text-body-lineHeight-medium,1.4285);}/*!sc*/ .eMMFM:where([data-size='large']){font-size:var(--text-body-size-large,1rem);line-height:var(--text-body-lineHeight-large,1.5);}/*!sc*/ .eMMFM:where([data-weight='light']){font-weight:var(--base-text-weight-light,300);}/*!sc*/ .eMMFM:where([data-weight='normal']){font-weight:var(--base-text-weight-normal,400);}/*!sc*/ .eMMFM:where([data-weight='medium']){font-weight:var(--base-text-weight-medium,500);}/*!sc*/ .eMMFM:where([data-weight='semibold']){font-weight:var(--base-text-weight-semibold,600);}/*!sc*/ .HlHVj{padding-left:4px;padding-right:4px;font-weight:400;color:var(--fgColor-muted,var(--color-fg-muted,#656d76));font-size:16px;}/*!sc*/ .HlHVj:where([data-size='small']){font-size:var(--text-body-size-small,0.75rem);line-height:var(--text-body-lineHeight-small,1.6666);}/*!sc*/ .HlHVj:where([data-size='medium']){font-size:var(--text-body-size-medium,0.875rem);line-height:var(--text-body-lineHeight-medium,1.4285);}/*!sc*/ .HlHVj:where([data-size='large']){font-size:var(--text-body-size-large,1rem);line-height:var(--text-body-lineHeight-large,1.5);}/*!sc*/ .HlHVj:where([data-weight='light']){font-weight:var(--base-text-weight-light,300);}/*!sc*/ .HlHVj:where([data-weight='normal']){font-weight:var(--base-text-weight-normal,400);}/*!sc*/ .HlHVj:where([data-weight='medium']){font-weight:var(--base-text-weight-medium,500);}/*!sc*/ .HlHVj:where([data-weight='semibold']){font-weight:var(--base-text-weight-semibold,600);}/*!sc*/ .lauzFl{padding-left:4px;padding-right:4px;font-weight:400;color:var(--fgColor-muted,var(--color-fg-muted,#656d76));font-size:14px;}/*!sc*/ .lauzFl:where([data-size='small']){font-size:var(--text-body-size-small,0.75rem);line-height:var(--text-body-lineHeight-small,1.6666);}/*!sc*/ .lauzFl:where([data-size='medium']){font-size:var(--text-body-size-medium,0.875rem);line-height:var(--text-body-lineHeight-medium,1.4285);}/*!sc*/ .lauzFl:where([data-size='large']){font-size:var(--text-body-size-large,1rem);line-height:var(--text-body-lineHeight-large,1.5);}/*!sc*/ .lauzFl:where([data-weight='light']){font-weight:var(--base-text-weight-light,300);}/*!sc*/ .lauzFl:where([data-weight='normal']){font-weight:var(--base-text-weight-normal,400);}/*!sc*/ .lauzFl:where([data-weight='medium']){font-weight:var(--base-text-weight-medium,500);}/*!sc*/ .lauzFl:where([data-weight='semibold']){font-weight:var(--base-text-weight-semibold,600);}/*!sc*/ data-styled.g3[id="Text__StyledText-sc-17v1xeu-0"]{content:"eMMFM,HlHVj,lauzFl,"}/*!sc*/ .jkNcAv{border:0;font-size:inherit;font-family:inherit;background-color:transparent;-webkit-appearance:none;color:inherit;width:100%;}/*!sc*/ .jkNcAv:focus{outline:0;}/*!sc*/ data-styled.g13[id="UnstyledTextInput__ToggledUnstyledTextInput-sc-14ypya-0"]{content:"jkNcAv,"}/*!sc*/ .hLzFvi{font-size:14px;line-height:var(--base-size-20);color:var(--fgColor-default,var(--color-fg-default,#1F2328));vertical-align:middle;background-color:var(--bgColor-default,var(--color-canvas-default,#ffffff));border:1px solid var(--control-borderColor-rest,var(--borderColor-default,var(--color-border-default,#d0d7de)));border-radius:6px;outline:none;box-shadow:var(--shadow-inset,var(--color-primer-shadow-inset,inset 0 1px 0 rgba(208,215,222,0.2)));display:-webkit-inline-box;display:-webkit-inline-flex;display:-ms-inline-flexbox;display:inline-flex;-webkit-align-items:stretch;-webkit-box-align:stretch;-ms-flex-align:stretch;align-items:stretch;min-height:var(--base-size-32);overflow:hidden;--inner-action-size:var(--base-size-24);}/*!sc*/ .hLzFvi input,.hLzFvi textarea{cursor:text;}/*!sc*/ .hLzFvi select{cursor:pointer;}/*!sc*/ .hLzFvi input::-webkit-input-placeholder,.hLzFvi textarea::-webkit-input-placeholder,.hLzFvi select::-webkit-input-placeholder{color:var(---control-fgColor-placeholder,var(--fgColor-muted,var(--color-fg-muted,#656d76)));}/*!sc*/ .hLzFvi input::-moz-placeholder,.hLzFvi textarea::-moz-placeholder,.hLzFvi select::-moz-placeholder{color:var(---control-fgColor-placeholder,var(--fgColor-muted,var(--color-fg-muted,#656d76)));}/*!sc*/ .hLzFvi input:-ms-input-placeholder,.hLzFvi textarea:-ms-input-placeholder,.hLzFvi select:-ms-input-placeholder{color:var(---control-fgColor-placeholder,var(--fgColor-muted,var(--color-fg-muted,#656d76)));}/*!sc*/ .hLzFvi input::placeholder,.hLzFvi textarea::placeholder,.hLzFvi select::placeholder{color:var(---control-fgColor-placeholder,var(--fgColor-muted,var(--color-fg-muted,#656d76)));}/*!sc*/ .hLzFvi:where([data-trailing-action][data-focused]),.hLzFvi:where(:not([data-trailing-action]):focus-within){border-color:var(--fgColor-accent,var(--color-accent-fg,#0969da));outline:2px solid var(--fgColor-accent,var(--color-accent-fg,#0969da));outline-offset:-1px;}/*!sc*/ .hLzFvi > textarea{padding:var(--base-size-12);}/*!sc*/ .hLzFvi:where([data-contrast]){background-color:var(--bgColor-inset,var(--color-canvas-inset,#f6f8fa));}/*!sc*/ .hLzFvi:where([data-disabled]){color:var(--fgColor-disabled,var(--color-primer-fg-disabled,#8c959f));background-color:var(--control-bgColor-disabled,var(--color-input-disabled-bg,rgba(175,184,193,0.2)));box-shadow:none;border-color:var(--control-borderColor-disabled,var(--borderColor-default,var(--color-border-default,#d0d7de)));}/*!sc*/ .hLzFvi:where([data-disabled]) input,.hLzFvi:where([data-disabled]) textarea,.hLzFvi:where([data-disabled]) select{cursor:not-allowed;}/*!sc*/ .hLzFvi:where([data-monospace]){font-family:var(--fontStack-monospace,SFMono-Regular,Consolas,"Liberation Mono",Menlo,Courier,monospace);}/*!sc*/ .hLzFvi:where([data-validation='error']){border-color:var(--borderColor-danger-emphasis,var(--color-danger-emphasis,#cf222e));}/*!sc*/ .hLzFvi:where([data-validation='error']):where([data-trailing-action][data-focused]),.hLzFvi:where([data-validation='error']):where(:not([data-trailing-action])):focus-within{border-color:var(--fgColor-accent,var(--color-accent-fg,#0969da));outline:2px solid var(--fgColor-accent,var(--color-accent-fg,#0969da));outline-offset:-1px;}/*!sc*/ .hLzFvi:where([data-validation='success']){border-color:var(--bgColor-success-emphasis,var(--color-success-emphasis,#1f883d));}/*!sc*/ .hLzFvi:where([data-block]){width:100%;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-self:stretch;-ms-flex-item-align:stretch;align-self:stretch;}/*!sc*/ @media (min-width:768px){.hLzFvi{font-size:var(--text-body-size-medium);}}/*!sc*/ .hLzFvi:where([data-size='small']){--inner-action-size:var(--base-size-20);min-height:var(--base-size-28);padding-top:3px;padding-right:var(--base-size-8);padding-bottom:3px;padding-left:var(--base-size-8);font-size:var(--text-body-size-small);line-height:var(--base-size-20);}/*!sc*/ .hLzFvi:where([data-size='large']){--inner-action-size:var(--base-size-28);height:var(--base-size-40);padding-top:10px;padding-right:var(--base-size-8);padding-bottom:10px;padding-left:var(--base-size-8);}/*!sc*/ .hLzFvi:where([data-variant='small']){min-height:28px;padding-top:3px;padding-right:var(--base-size-8);padding-bottom:3px;padding-left:var(--base-size-8);font-size:(--text-body-size-small);line-height:var(--base-size-20);}/*!sc*/ .hLzFvi:where([data-variant='large']){padding-top:10px;padding-right:var(--base-size-8);padding-bottom:10px;padding-left:var(--base-size-8);font-size:var(--text-title-size-medium);}/*!sc*/ .hLzFvi{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;min-width:160px;}/*!sc*/ data-styled.g14[id="TextInputWrapper__StyledTextInputBaseWrapper-sc-1mqhpbi-0"]{content:"hLzFvi,"}/*!sc*/ .iHYdQq{background-repeat:no-repeat;background-position:right 8px center;padding-right:0;padding-left:0;}/*!sc*/ .iHYdQq > :not(:last-child){margin-right:8px;}/*!sc*/ .iHYdQq .TextInput-icon,.iHYdQq .TextInput-action{-webkit-align-self:center;-ms-flex-item-align:center;align-self:center;color:var(--fgColor-muted,var(--color-fg-muted,#656d76));-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0;}/*!sc*/ .iHYdQq > input,.iHYdQq > select{padding-right:0;padding-left:0;}/*!sc*/ .iHYdQq:where([data-leading-visual]){padding-left:var(--base-size-12);}/*!sc*/ .iHYdQq:where([data-trailing-visual]:not([data-trailing-action])){padding-right:var(--base-size-12);}/*!sc*/ .iHYdQq:where(:not([data-leading-visual])) > input,.iHYdQq:where(:not([data-leading-visual])) > select{padding-left:var(--base-size-12);}/*!sc*/ .iHYdQq:where(:not([data-trailing-visual]):not([data-trailing-action])) > input,.iHYdQq:where(:not([data-trailing-visual]):not([data-trailing-action])) > select{padding-right:var(--base-size-12);}/*!sc*/ .iHYdQq{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;min-width:160px;}/*!sc*/ data-styled.g15[id="TextInputWrapper__StyledTextInputWrapper-sc-1mqhpbi-1"]{content:"iHYdQq,"}/*!sc*/ .jOyaRH{display:none;}/*!sc*/ .jOyaRH[popover]{position:absolute;padding:0.5em 0.75em;width:-webkit-max-content;width:-moz-max-content;width:max-content;margin:auto;-webkit-clip:auto;clip:auto;white-space:normal;font:normal normal 11px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI","Noto Sans",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";-webkit-font-smoothing:subpixel-antialiased;color:var(--tooltip-fgColor,var(--fgColor-onEmphasis,var(--color-fg-on-emphasis,#ffffff)));text-align:center;word-wrap:break-word;background:var(--tooltip-bgColor,var(--bgColor-emphasis,var(--color-neutral-emphasis-plus,#24292f)));border-radius:6px;border:0;opacity:0;max-width:250px;inset:auto;overflow:visible;}/*!sc*/ .jOyaRH[popover]:popover-open{display:block;}/*!sc*/ .jOyaRH[popover].\:popover-open{display:block;}/*!sc*/ @media (forced-colors:active){.jOyaRH{outline:1px solid transparent;}}/*!sc*/ .jOyaRH::after{position:absolute;display:block;right:0;left:0;height:var(--overlay-offset,0.25rem);content:'';}/*!sc*/ .jOyaRH[data-direction='n']::after,.jOyaRH[data-direction='ne']::after,.jOyaRH[data-direction='nw']::after{top:100%;}/*!sc*/ .jOyaRH[data-direction='s']::after,.jOyaRH[data-direction='se']::after,.jOyaRH[data-direction='sw']::after{bottom:100%;}/*!sc*/ .jOyaRH[data-direction='w']::after{position:absolute;display:block;height:100%;width:8px;content:'';bottom:0;left:100%;}/*!sc*/ .jOyaRH[data-direction='e']::after{position:absolute;display:block;height:100%;width:8px;content:'';bottom:0;right:100%;margin-left:-8px;}/*!sc*/ @-webkit-keyframes tooltip-appear{from{opacity:0;}to{opacity:1;}}/*!sc*/ @keyframes tooltip-appear{from{opacity:0;}to{opacity:1;}}/*!sc*/ .jOyaRH:popover-open,.jOyaRH:popover-open::before{-webkit-animation-name:tooltip-appear;animation-name:tooltip-appear;-webkit-animation-duration:0.1s;animation-duration:0.1s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in;-webkit-animation-delay:0s;animation-delay:0s;}/*!sc*/ .jOyaRH.\:popover-open,.jOyaRH.\:popover-open::before{-webkit-animation-name:tooltip-appear;animation-name:tooltip-appear;-webkit-animation-duration:0.1s;animation-duration:0.1s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in;-webkit-animation-delay:0s;animation-delay:0s;}/*!sc*/ data-styled.g16[id="Tooltip__StyledTooltip-sc-e45c7z-0"]{content:"jOyaRH,"}/*!sc*/ .hWlpPn{position:relative;display:inline-block;}/*!sc*/ .hWlpPn::after{position:absolute;z-index:1000000;display:none;padding:0.5em 0.75em;font:normal normal 11px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI","Noto Sans",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";-webkit-font-smoothing:subpixel-antialiased;color:var(--tooltip-fgColor,var(--fgColor-onEmphasis,var(--color-fg-on-emphasis,#ffffff)));text-align:center;-webkit-text-decoration:none;text-decoration:none;text-shadow:none;text-transform:none;-webkit-letter-spacing:normal;-moz-letter-spacing:normal;-ms-letter-spacing:normal;letter-spacing:normal;word-wrap:break-word;white-space:pre;pointer-events:none;content:attr(aria-label);background:var(--tooltip-bgColor,var(--bgColor-emphasis,var(--color-neutral-emphasis-plus,#24292f)));border-radius:6px;opacity:0;}/*!sc*/ @-webkit-keyframes tooltip-appear{from{opacity:0;}to{opacity:1;}}/*!sc*/ @keyframes tooltip-appear{from{opacity:0;}to{opacity:1;}}/*!sc*/ .hWlpPn:hover::after,.hWlpPn:active::after,.hWlpPn:focus::after,.hWlpPn:focus-within::after{display:inline-block;-webkit-text-decoration:none;text-decoration:none;-webkit-animation-name:tooltip-appear;animation-name:tooltip-appear;-webkit-animation-duration:0.1s;animation-duration:0.1s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in;-webkit-animation-delay:0s;animation-delay:0s;}/*!sc*/ .hWlpPn.tooltipped-no-delay:hover::after,.hWlpPn.tooltipped-no-delay:active::after,.hWlpPn.tooltipped-no-delay:focus::after,.hWlpPn.tooltipped-no-delay:focus-within::after{-webkit-animation-delay:0s;animation-delay:0s;}/*!sc*/ .hWlpPn.tooltipped-multiline:hover::after,.hWlpPn.tooltipped-multiline:active::after,.hWlpPn.tooltipped-multiline:focus::after,.hWlpPn.tooltipped-multiline:focus-within::after{display:table-cell;}/*!sc*/ .hWlpPn.tooltipped-s::after,.hWlpPn.tooltipped-se::after,.hWlpPn.tooltipped-sw::after{top:100%;right:50%;margin-top:6px;}/*!sc*/ .hWlpPn.tooltipped-se::after{right:auto;left:50%;margin-left:-16px;}/*!sc*/ .hWlpPn.tooltipped-sw::after{margin-right:-16px;}/*!sc*/ .hWlpPn.tooltipped-n::after,.hWlpPn.tooltipped-ne::after,.hWlpPn.tooltipped-nw::after{right:50%;bottom:100%;margin-bottom:6px;}/*!sc*/ .hWlpPn.tooltipped-ne::after{right:auto;left:50%;margin-left:-16px;}/*!sc*/ .hWlpPn.tooltipped-nw::after{margin-right:-16px;}/*!sc*/ .hWlpPn.tooltipped-s::after,.hWlpPn.tooltipped-n::after{-webkit-transform:translateX(50%);-ms-transform:translateX(50%);transform:translateX(50%);}/*!sc*/ .hWlpPn.tooltipped-w::after{right:100%;bottom:50%;margin-right:6px;-webkit-transform:translateY(50%);-ms-transform:translateY(50%);transform:translateY(50%);}/*!sc*/ .hWlpPn.tooltipped-e::after{bottom:50%;left:100%;margin-left:6px;-webkit-transform:translateY(50%);-ms-transform:translateY(50%);transform:translateY(50%);}/*!sc*/ .hWlpPn.tooltipped-multiline::after{width:-webkit-max-content;width:-moz-max-content;width:max-content;max-width:250px;word-wrap:break-word;white-space:pre-line;border-collapse:separate;}/*!sc*/ .hWlpPn.tooltipped-multiline.tooltipped-s::after,.hWlpPn.tooltipped-multiline.tooltipped-n::after{right:auto;left:50%;-webkit-transform:translateX(-50%);-ms-transform:translateX(-50%);transform:translateX(-50%);}/*!sc*/ .hWlpPn.tooltipped-multiline.tooltipped-w::after,.hWlpPn.tooltipped-multiline.tooltipped-e::after{right:100%;}/*!sc*/ .hWlpPn.tooltipped-align-right-2::after{right:0;margin-right:0;}/*!sc*/ .hWlpPn.tooltipped-align-left-2::after{left:0;margin-left:0;}/*!sc*/ data-styled.g17[id="Tooltip__TooltipBase-sc-17tf59c-0"]{content:"hWlpPn,"}/*!sc*/ .eAtkQz{display:inline-block;overflow:hidden;text-overflow:ellipsis;vertical-align:top;white-space:nowrap;max-width:125px;max-width:100%;}/*!sc*/ data-styled.g19[id="Truncate__StyledTruncate-sc-23o1d2-0"]{content:"eAtkQz,"}/*!sc*/ .dwImxt{--segmented-control-button-inner-padding:12px;--segmented-control-button-bg-inset:4px;--segmented-control-outer-radius:6px;background-color:transparent;border-color:transparent;border-radius:var(--segmented-control-outer-radius);border-width:0;color:currentColor;cursor:pointer;font-family:inherit;font-size:inherit;font-weight:600;padding:0;height:100%;width:100%;}/*!sc*/ .dwImxt:focus:not(:disabled){box-shadow:none;outline:2px solid var(--fgColor-accent,var(--color-accent-fg,#0969da));outline-offset:-1px;}/*!sc*/ .dwImxt:focus:not(:disabled):not(:focus-visible){outline:solid 1px transparent;}/*!sc*/ .dwImxt:focus-visible:not(:disabled){box-shadow:none;outline:2px solid var(--fgColor-accent,var(--color-accent-fg,#0969da));outline-offset:-1px;}/*!sc*/ .dwImxt .segmentedControl-content{-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;background-color:var(--controlKnob-bgColor-rest,var(--color-segmented-control-button-bg,#ffffff));border-color:var(--controlKnob-borderColor-rest,var(--color-segmented-control-button-hover-active-selected-border,#8c959f));border-style:solid;border-width:1px;border-radius:var(--segmented-control-outer-radius);display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;height:100%;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;padding-left:var(--segmented-control-button-inner-padding);padding-right:var(--segmented-control-button-inner-padding);}/*!sc*/ .dwImxt svg{fill:var(--fgColor-muted,var(--color-fg-muted,#656d76));}/*!sc*/ .dwImxt:focus:focus-visible:not(:last-child):after{width:0;}/*!sc*/ .dwImxt .segmentedControl-text:after{content:"Preview";display:block;font-weight:600;height:0;overflow:hidden;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;visibility:hidden;}/*!sc*/ @media (pointer:coarse){.dwImxt:before{content:"";position:absolute;left:0;right:0;-webkit-transform:translateY(-50%);-ms-transform:translateY(-50%);transform:translateY(-50%);top:50%;min-height:44px;}}/*!sc*/ .iFTkun{--segmented-control-button-inner-padding:12px;--segmented-control-button-bg-inset:4px;--segmented-control-outer-radius:6px;background-color:transparent;border-color:transparent;border-radius:var(--segmented-control-outer-radius);border-width:0;color:currentColor;cursor:pointer;font-family:inherit;font-size:inherit;font-weight:400;padding:var(--segmented-control-button-bg-inset);height:100%;width:100%;}/*!sc*/ .iFTkun:focus:not(:disabled){box-shadow:none;outline:2px solid var(--fgColor-accent,var(--color-accent-fg,#0969da));outline-offset:-1px;}/*!sc*/ .iFTkun:focus:not(:disabled):not(:focus-visible){outline:solid 1px transparent;}/*!sc*/ .iFTkun:focus-visible:not(:disabled){box-shadow:none;outline:2px solid var(--fgColor-accent,var(--color-accent-fg,#0969da));outline-offset:-1px;}/*!sc*/ .iFTkun .segmentedControl-content{-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;background-color:transparent;border-color:transparent;border-style:solid;border-width:1px;border-radius:calc(var(--segmented-control-outer-radius) - var(--segmented-control-button-bg-inset) / 2);display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;height:100%;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;padding-left:calc(var(--segmented-control-button-inner-padding) - var(--segmented-control-button-bg-inset));padding-right:calc(var(--segmented-control-button-inner-padding) - var(--segmented-control-button-bg-inset));}/*!sc*/ .iFTkun svg{fill:var(--fgColor-muted,var(--color-fg-muted,#656d76));}/*!sc*/ .iFTkun:hover .segmentedControl-content{background-color:var(--controlTrack-bgColor-hover,var(--color-segmented-control-button-hover-bg,rgba(175,184,193,0.2)));}/*!sc*/ .iFTkun:active .segmentedControl-content{background-color:var(--controlTrack-bgColor-active,var(--color-segmented-control-button-hover-active-bg,rgba(175,184,193,0.4)));}/*!sc*/ .iFTkun:focus:focus-visible:not(:last-child):after{width:0;}/*!sc*/ .iFTkun .segmentedControl-text:after{content:"Code";display:block;font-weight:600;height:0;overflow:hidden;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;visibility:hidden;}/*!sc*/ @media (pointer:coarse){.iFTkun:before{content:"";position:absolute;left:0;right:0;-webkit-transform:translateY(-50%);-ms-transform:translateY(-50%);transform:translateY(-50%);top:50%;min-height:44px;}}/*!sc*/ .bHmvop{--segmented-control-button-inner-padding:12px;--segmented-control-button-bg-inset:4px;--segmented-control-outer-radius:6px;background-color:transparent;border-color:transparent;border-radius:var(--segmented-control-outer-radius);border-width:0;color:currentColor;cursor:pointer;font-family:inherit;font-size:inherit;font-weight:400;padding:var(--segmented-control-button-bg-inset);height:100%;width:100%;}/*!sc*/ .bHmvop:focus:not(:disabled){box-shadow:none;outline:2px solid var(--fgColor-accent,var(--color-accent-fg,#0969da));outline-offset:-1px;}/*!sc*/ .bHmvop:focus:not(:disabled):not(:focus-visible){outline:solid 1px transparent;}/*!sc*/ .bHmvop:focus-visible:not(:disabled){box-shadow:none;outline:2px solid var(--fgColor-accent,var(--color-accent-fg,#0969da));outline-offset:-1px;}/*!sc*/ .bHmvop .segmentedControl-content{-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;background-color:transparent;border-color:transparent;border-style:solid;border-width:1px;border-radius:calc(var(--segmented-control-outer-radius) - var(--segmented-control-button-bg-inset) / 2);display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;height:100%;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;padding-left:calc(var(--segmented-control-button-inner-padding) - var(--segmented-control-button-bg-inset));padding-right:calc(var(--segmented-control-button-inner-padding) - var(--segmented-control-button-bg-inset));}/*!sc*/ .bHmvop svg{fill:var(--fgColor-muted,var(--color-fg-muted,#656d76));}/*!sc*/ .bHmvop:hover .segmentedControl-content{background-color:var(--controlTrack-bgColor-hover,var(--color-segmented-control-button-hover-bg,rgba(175,184,193,0.2)));}/*!sc*/ .bHmvop:active .segmentedControl-content{background-color:var(--controlTrack-bgColor-active,var(--color-segmented-control-button-hover-active-bg,rgba(175,184,193,0.4)));}/*!sc*/ .bHmvop:focus:focus-visible:not(:last-child):after{width:0;}/*!sc*/ .bHmvop .segmentedControl-text:after{content:"Blame";display:block;font-weight:600;height:0;overflow:hidden;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;visibility:hidden;}/*!sc*/ @media (pointer:coarse){.bHmvop:before{content:"";position:absolute;left:0;right:0;-webkit-transform:translateY(-50%);-ms-transform:translateY(-50%);transform:translateY(-50%);top:50%;min-height:44px;}}/*!sc*/ data-styled.g105[id="SegmentedControlButton__SegmentedControlButtonStyled-sc-8lkgxl-0"]{content:"dwImxt,iFTkun,bHmvop,"}/*!sc*/ .lawgDG{background-color:var(--controlTrack-bgColor-rest,var(--color-segmented-control-bg,#eaeef2));border-radius:6px;border:1px solid;border-color:var(--controlTrack-borderColor-rest,transparent);display:-webkit-inline-box;display:-webkit-inline-flex;display:-ms-inline-flexbox;display:inline-flex;font-size:14px;height:28px;margin:0;padding:0;}/*!sc*/ data-styled.g107[id="SegmentedControl__SegmentedControlList-sc-1rzig82-0"]{content:"lawgDG,"}/*!sc*/ body[data-page-layout-dragging="true"]{cursor:col-resize;}/*!sc*/ body[data-page-layout-dragging="true"] *{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;}/*!sc*/ data-styled.g108[id="sc-global-gbKrvU1"]{content:"sc-global-gbKrvU1,"}/*!sc*/ </style><meta data-hydrostats="publish"/> <!-- --> <!-- --> <button hidden="" data-testid="header-permalink-button" data-hotkey-scope="read-only-cursor-text-area"></button><button hidden=""></button><div><div style="--sticky-pane-height:100vh;--spacing:var(--spacing-none)" class="Box-sc-g0xbh4-0 hOfjFo"><div class="Box-sc-g0xbh4-0 oDGAe"><div class="Box-sc-g0xbh4-0 kowOcT"><div tabindex="0" class="Box-sc-g0xbh4-0 gISSDQ"><div class="Box-sc-g0xbh4-0 cEmWSE"><div class="Box-sc-g0xbh4-0 hPvFuC"></div><div style="--pane-width:320px" class="Box-sc-g0xbh4-0 fFSoPl"></div><div class="Box-sc-g0xbh4-0 bTBnTW"><div role="slider" aria-label="Draggable pane splitter" aria-valuemin="0" aria-valuemax="0" aria-valuenow="0" aria-valuetext="Pane width 0 pixels" tabindex="0" class="Box-sc-g0xbh4-0 bHLmSv"></div></div></div></div><div class="Box-sc-g0xbh4-0 iKqMNA"><div class="Box-sc-g0xbh4-0"></div><div class="Box-sc-g0xbh4-0 FxAyp"><div data-selector="repos-split-pane-content" tabindex="0" class="Box-sc-g0xbh4-0 leYMvG"><div class="Box-sc-g0xbh4-0 KMPzq"><div class="Box-sc-g0xbh4-0 hfKjHv container"><div class="px-3 pt-3 pb-0" id="StickyHeader"><div class="Box-sc-g0xbh4-0 gZWyZE"><div class="Box-sc-g0xbh4-0 dwYKDk"><div class="Box-sc-g0xbh4-0 ibcGmb react-code-view-header-wrap--narrow"><div class="Box-sc-g0xbh4-0 hKaEJF"><h2 class="Box-sc-g0xbh4-0 XosP prc-Heading-Heading-6CmGO"><button style="--button-color:fg.muted" type="button" aria-label="Expand file tree" data-testid="expand-file-tree-button-mobile" class="Box-sc-g0xbh4-0 bCKfWo prc-Button-ButtonBase-c50BI" data-loading="false" data-size="medium" data-variant="invisible" aria-describedby=":Rld9lab:-loading-announcement"><span data-component="buttonContent" class="Box-sc-g0xbh4-0 gUkoLg prc-Button-ButtonContent-HKbr-"><span data-component="leadingVisual" class="prc-Button-Visual-2epfX prc-Button-VisualWrap-Db-eB"><svg aria-hidden="true" focusable="false" class="octicon octicon-arrow-left" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" style="display:inline-block;user-select:none;vertical-align:text-bottom;overflow:visible"><path d="M7.78 12.53a.75.75 0 0 1-1.06 0L2.47 8.28a.75.75 0 0 1 0-1.06l4.25-4.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042L4.81 7h7.44a.75.75 0 0 1 0 1.5H4.81l2.97 2.97a.75.75 0 0 1 0 1.06Z"></path></svg></span><span data-component="text" class="prc-Button-Label-pTQ3x">Files</span></span></button><span role="tooltip" aria-label="Expand file tree" id="expand-button-file-tree-button" class="Tooltip__TooltipBase-sc-17tf59c-0 hWlpPn tooltipped-se"><button data-component="IconButton" type="button" data-testid="expand-file-tree-button" aria-controls="repos-file-tree" class="prc-Button-ButtonBase-c50BI position-relative ExpandFileTreeButton-module__expandButton--gL4is ExpandFileTreeButton-module__filesButtonBreakpoint--WfX9t fgColor-muted prc-Button-IconButton-szpyj" data-loading="false" data-no-visuals="true" data-size="medium" data-variant="invisible" aria-describedby=":R35d9lab:-loading-announcement" aria-labelledby="expand-button-file-tree-button"><svg aria-hidden="true" focusable="false" class="octicon octicon-sidebar-collapse" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" style="display:inline-block;user-select:none;vertical-align:text-bottom;overflow:visible"><path d="M6.823 7.823a.25.25 0 0 1 0 .354l-2.396 2.396A.25.25 0 0 1 4 10.396V5.604a.25.25 0 0 1 .427-.177Z"></path><path d="M1.75 0h12.5C15.216 0 16 .784 16 1.75v12.5A1.75 1.75 0 0 1 14.25 16H1.75A1.75 1.75 0 0 1 0 14.25V1.75C0 .784.784 0 1.75 0ZM1.5 1.75v12.5c0 .138.112.25.25.25H9.5v-13H1.75a.25.25 0 0 0-.25.25ZM11 14.5h3.25a.25.25 0 0 0 .25-.25V1.75a.25.25 0 0 0-.25-.25H11Z"></path></svg></button></span><button hidden="" data-testid="" data-hotkey-scope="read-only-cursor-text-area"></button></h2></div><div class="react-code-view-header-mb--narrow mr-2"><button type="button" aria-haspopup="true" aria-expanded="false" tabindex="0" aria-label="master branch" data-testid="anchor-button" class="Box-sc-g0xbh4-0 dmxRgG prc-Button-ButtonBase-c50BI ref-selector-class" data-loading="false" data-size="medium" data-variant="default" aria-describedby="branch-picker-repos-header-ref-selector-wide-loading-announcement" id="branch-picker-repos-header-ref-selector-wide"><span data-component="buttonContent" class="Box-sc-g0xbh4-0 gUkoLg prc-Button-ButtonContent-HKbr-"><span data-component="text" class="prc-Button-Label-pTQ3x"><div class="Box-sc-g0xbh4-0 bZBlpz"><div class="Box-sc-g0xbh4-0 lhTYNA"><svg aria-hidden="true" focusable="false" class="octicon octicon-git-branch" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" style="display:inline-block;user-select:none;vertical-align:text-bottom;overflow:visible"><path d="M9.5 3.25a2.25 2.25 0 1 1 3 2.122V6A2.5 2.5 0 0 1 10 8.5H6a1 1 0 0 0-1 1v1.128a2.251 2.251 0 1 1-1.5 0V5.372a2.25 2.25 0 1 1 1.5 0v1.836A2.493 2.493 0 0 1 6 7h4a1 1 0 0 0 1-1v-.628A2.25 2.25 0 0 1 9.5 3.25Zm-6 0a.75.75 0 1 0 1.5 0 .75.75 0 0 0-1.5 0Zm8.25-.75a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5ZM4.25 12a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Z"></path></svg></div><div class="Box-sc-g0xbh4-0 dbrgmi ref-selector-button-text-container"><span class="Text__StyledText-sc-17v1xeu-0 eMMFM"> <!-- -->master</span></div></div></span><span data-component="trailingVisual" class="prc-Button-Visual-2epfX prc-Button-VisualWrap-Db-eB"><svg aria-hidden="true" focusable="false" class="octicon octicon-triangle-down" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" style="display:inline-block;user-select:none;vertical-align:text-bottom;overflow:visible"><path d="m4.427 7.427 3.396 3.396a.25.25 0 0 0 .354 0l3.396-3.396A.25.25 0 0 0 11.396 7H4.604a.25.25 0 0 0-.177.427Z"></path></svg></span></span></button><button hidden="" data-hotkey-scope="read-only-cursor-text-area"></button></div><div class="Box-sc-g0xbh4-0 dHJiml react-code-view-header-mb--narrow"><div class="Box-sc-g0xbh4-0 cEytCf"><nav data-testid="breadcrumbs" aria-labelledby="repos-header-breadcrumb-heading" id="repos-header-breadcrumb" class="Box-sc-g0xbh4-0 fzFXnm"><h2 class="sr-only ScreenReaderHeading-module__userSelectNone--vW4Cq prc-Heading-Heading-6CmGO" data-testid="screen-reader-heading" id="repos-header-breadcrumb-heading">Breadcrumbs</h2><ol class="Box-sc-g0xbh4-0 iMnkmv"><li class="Box-sc-g0xbh4-0 ghzDag"><a class="Box-sc-g0xbh4-0 kHuKdh prc-Link-Link-85e08" sx="[object Object]" data-testid="breadcrumbs-repo-link" href="/google/cel-spec/tree/master">cel-spec</a></li><li class="Box-sc-g0xbh4-0 ghzDag"><span class="Text__StyledText-sc-17v1xeu-0 HlHVj" aria-hidden="true">/</span><a class="Box-sc-g0xbh4-0 kgiVEz prc-Link-Link-85e08" sx="[object Object]" href="/google/cel-spec/tree/master/doc">doc</a></li></ol></nav><div data-testid="breadcrumbs-filename" class="Box-sc-g0xbh4-0 ghzDag"><span class="Text__StyledText-sc-17v1xeu-0 HlHVj" aria-hidden="true">/</span><h1 class="Box-sc-g0xbh4-0 jGhzSQ prc-Heading-Heading-6CmGO" tabindex="-1" id="file-name-id">langdef.md</h1></div><button data-component="IconButton" type="button" class="prc-Button-ButtonBase-c50BI ml-2 prc-Button-IconButton-szpyj" data-loading="false" data-no-visuals="true" data-size="small" data-variant="invisible" aria-describedby=":Rftd9lab:-loading-announcement" aria-labelledby=":R1td9lab:"><svg aria-hidden="true" focusable="false" class="octicon octicon-copy" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" style="display:inline-block;user-select:none;vertical-align:text-bottom;overflow:visible"><path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path><path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path></svg></button><span class="Tooltip__StyledTooltip-sc-e45c7z-0 jOyaRH CopyToClipboardButton-module__tooltip--Dq1IB" data-direction="nw" aria-label="Copy path" aria-hidden="true" id=":R1td9lab:">Copy path</span></div></div></div><div class="react-code-view-header-element--wide"><div class="Box-sc-g0xbh4-0 faNtbn"><div class="d-flex gap-2"> <div><div class="Box-sc-g0xbh4-0 fmQaBv"><span class="TextInputWrapper__StyledTextInputBaseWrapper-sc-1mqhpbi-0 hLzFvi TextInputWrapper__StyledTextInputWrapper-sc-1mqhpbi-1 iHYdQq TextInput-wrapper" data-leading-visual="true" data-trailing-visual="true" aria-busy="false"><span class="TextInput-icon" id=":R5j6d9lab:" aria-hidden="true"><svg aria-hidden="true" focusable="false" class="octicon octicon-search" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" style="display:inline-block;user-select:none;vertical-align:text-bottom;overflow:visible"><path d="M10.68 11.74a6 6 0 0 1-7.922-8.982 6 6 0 0 1 8.982 7.922l3.04 3.04a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215ZM11.5 7a4.499 4.499 0 1 0-8.997 0A4.499 4.499 0 0 0 11.5 7Z"></path></svg></span><input type="text" aria-label="Go to file" role="combobox" aria-controls="file-results-list" aria-expanded="false" aria-haspopup="dialog" autoCorrect="off" spellcheck="false" placeholder="Go to file" aria-describedby=":R5j6d9lab: :R5j6d9labH1:" data-component="input" class="UnstyledTextInput__ToggledUnstyledTextInput-sc-14ypya-0 jkNcAv" value=""/><span class="TextInput-icon" id=":R5j6d9labH1:" aria-hidden="true"></span></span></div><button hidden="" data-testid="" data-hotkey-scope="read-only-cursor-text-area"></button><button hidden=""></button></div><button type="button" class="Box-sc-g0xbh4-0 dwNhzn prc-Button-ButtonBase-c50BI" data-loading="false" data-no-visuals="true" data-size="medium" data-variant="default" aria-describedby=":R2l6d9lab:-loading-announcement"><span data-component="buttonContent" class="Box-sc-g0xbh4-0 gUkoLg prc-Button-ButtonContent-HKbr-"><span data-component="text" class="prc-Button-Label-pTQ3x">Blame</span></span></button><button hidden="" data-testid="" data-hotkey-scope="read-only-cursor-text-area"></button><button data-component="IconButton" type="button" aria-label="More file actions" title="More file actions" data-testid="more-file-actions-button-nav-menu-wide" aria-haspopup="true" aria-expanded="false" tabindex="0" class="Box-sc-g0xbh4-0 fGwBZA prc-Button-ButtonBase-c50BI js-blob-dropdown-click prc-Button-IconButton-szpyj" data-loading="false" data-no-visuals="true" data-size="medium" data-variant="default" aria-describedby=":R156d9lab:-loading-announcement" id=":R156d9lab:"><svg aria-hidden="true" focusable="false" class="octicon octicon-kebab-horizontal" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" style="display:inline-block;user-select:none;vertical-align:text-bottom;overflow:visible"><path d="M8 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3ZM1.5 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Zm13 0a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"></path></svg></button> </div></div></div><div class="react-code-view-header-element--narrow"><div class="Box-sc-g0xbh4-0 faNtbn"><div class="d-flex gap-2"> <button type="button" class="Box-sc-g0xbh4-0 dwNhzn prc-Button-ButtonBase-c50BI" data-loading="false" data-no-visuals="true" data-size="medium" data-variant="default" aria-describedby=":R2l7d9lab:-loading-announcement"><span data-component="buttonContent" class="Box-sc-g0xbh4-0 gUkoLg prc-Button-ButtonContent-HKbr-"><span data-component="text" class="prc-Button-Label-pTQ3x">Blame</span></span></button><button hidden="" data-testid="" data-hotkey-scope="read-only-cursor-text-area"></button><button data-component="IconButton" type="button" aria-label="More file actions" title="More file actions" data-testid="more-file-actions-button-nav-menu-narrow" aria-haspopup="true" aria-expanded="false" tabindex="0" class="Box-sc-g0xbh4-0 fGwBZA prc-Button-ButtonBase-c50BI js-blob-dropdown-click prc-Button-IconButton-szpyj" data-loading="false" data-no-visuals="true" data-size="medium" data-variant="default" aria-describedby=":R157d9lab:-loading-announcement" id=":R157d9lab:"><svg aria-hidden="true" focusable="false" class="octicon octicon-kebab-horizontal" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" style="display:inline-block;user-select:none;vertical-align:text-bottom;overflow:visible"><path d="M8 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3ZM1.5 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Zm13 0a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"></path></svg></button> </div></div></div></div></div></div></div></div><div class="Box-sc-g0xbh4-0 dJxjrT react-code-view-bottom-padding"> <div class="Box-sc-g0xbh4-0 eFxKDQ"></div> <!-- --> <!-- --> </div><div class="Box-sc-g0xbh4-0 dJxjrT"> <!-- --> <!-- --> <button hidden="" data-testid="" data-hotkey-scope="read-only-cursor-text-area"></button><button hidden=""></button><div class="d-flex flex-column border rounded-2 mb-3 pl-1"><div class="Box-sc-g0xbh4-0 dzCJzi"><h2 class="sr-only ScreenReaderHeading-module__userSelectNone--vW4Cq prc-Heading-Heading-6CmGO" data-testid="screen-reader-heading">Latest commit</h2><div style="width:120px" class="Skeleton Skeleton--text" data-testid="loading"> </div><div class="d-flex flex-shrink-0 gap-2"><div data-testid="latest-commit-details" class="d-none d-sm-flex flex-items-center"></div><div class="d-flex gap-2"><h2 class="sr-only ScreenReaderHeading-module__userSelectNone--vW4Cq prc-Heading-Heading-6CmGO" data-testid="screen-reader-heading">History</h2><a href="/google/cel-spec/commits/master/doc/langdef.md" class="prc-Button-ButtonBase-c50BI d-none d-lg-flex LinkButton-module__code-view-link-button--xvCGA flex-items-center fgColor-default" data-loading="false" data-size="small" data-variant="invisible" aria-describedby=":R5dlal9lab:-loading-announcement"><span data-component="buttonContent" data-align="center" class="prc-Button-ButtonContent-HKbr-"><span data-component="leadingVisual" class="prc-Button-Visual-2epfX prc-Button-VisualWrap-Db-eB"><svg aria-hidden="true" focusable="false" class="octicon octicon-history" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" style="display:inline-block;user-select:none;vertical-align:text-bottom;overflow:visible"><path d="m.427 1.927 1.215 1.215a8.002 8.002 0 1 1-1.6 5.685.75.75 0 1 1 1.493-.154 6.5 6.5 0 1 0 1.18-4.458l1.358 1.358A.25.25 0 0 1 3.896 6H.25A.25.25 0 0 1 0 5.75V2.104a.25.25 0 0 1 .427-.177ZM7.75 4a.75.75 0 0 1 .75.75v2.992l2.028.812a.75.75 0 0 1-.557 1.392l-2.5-1A.751.751 0 0 1 7 8.25v-3.5A.75.75 0 0 1 7.75 4Z"></path></svg></span><span data-component="text" class="prc-Button-Label-pTQ3x"><span class="fgColor-default">History</span></span></span></a><div class="d-sm-none"></div><div class="d-flex d-lg-none"><span role="tooltip" aria-label="History" id="history-icon-button-tooltip" class="Tooltip__TooltipBase-sc-17tf59c-0 hWlpPn tooltipped-n"><a href="/google/cel-spec/commits/master/doc/langdef.md" class="prc-Button-ButtonBase-c50BI LinkButton-module__code-view-link-button--xvCGA flex-items-center fgColor-default" data-loading="false" data-size="small" data-variant="invisible" aria-describedby=":Rpdlal9lab:-loading-announcement history-icon-button-tooltip"><span data-component="buttonContent" data-align="center" class="prc-Button-ButtonContent-HKbr-"><span data-component="leadingVisual" class="prc-Button-Visual-2epfX prc-Button-VisualWrap-Db-eB"><svg aria-hidden="true" focusable="false" class="octicon octicon-history" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" style="display:inline-block;user-select:none;vertical-align:text-bottom;overflow:visible"><path d="m.427 1.927 1.215 1.215a8.002 8.002 0 1 1-1.6 5.685.75.75 0 1 1 1.493-.154 6.5 6.5 0 1 0 1.18-4.458l1.358 1.358A.25.25 0 0 1 3.896 6H.25A.25.25 0 0 1 0 5.75V2.104a.25.25 0 0 1 .427-.177ZM7.75 4a.75.75 0 0 1 .75.75v2.992l2.028.812a.75.75 0 0 1-.557 1.392l-2.5-1A.751.751 0 0 1 7 8.25v-3.5A.75.75 0 0 1 7.75 4Z"></path></svg></span></span></a></span></div></div></div></div></div><div class="Box-sc-g0xbh4-0 ldRxiI"><div class="Box-sc-g0xbh4-0 fVkfyA container"><div class="Box-sc-g0xbh4-0 gNAmSV react-code-size-details-banner"><div class="Box-sc-g0xbh4-0 jNEwzY react-code-size-details-banner"><div class="Box-sc-g0xbh4-0 bsDwxw text-mono"><div title="79.4 KB" data-testid="blob-size" class="Truncate__StyledTruncate-sc-23o1d2-0 eAtkQz"><span>2208 lines (1698 loc) · 79.4 KB</span></div></div></div></div><div class="Box-sc-g0xbh4-0 jdLMhu react-blob-view-header-sticky" id="repos-sticky-header"><div class="Box-sc-g0xbh4-0 tOISc"><div class="react-blob-sticky-header"><div class="Box-sc-g0xbh4-0 hqwSEx"><div class="Box-sc-g0xbh4-0 bDVoEr"><div class="Box-sc-g0xbh4-0 kYLlPM"><div class="Box-sc-g0xbh4-0 gYjEmn"><button type="button" aria-haspopup="true" aria-expanded="false" tabindex="0" aria-label="master branch" data-testid="anchor-button" class="Box-sc-g0xbh4-0 dmxRgG prc-Button-ButtonBase-c50BI ref-selector-class" data-loading="false" data-size="medium" data-variant="default" aria-describedby="branch-picker-repos-header-ref-selector-loading-announcement" id="branch-picker-repos-header-ref-selector"><span data-component="buttonContent" class="Box-sc-g0xbh4-0 gUkoLg prc-Button-ButtonContent-HKbr-"><span data-component="text" class="prc-Button-Label-pTQ3x"><div class="Box-sc-g0xbh4-0 bZBlpz"><div class="Box-sc-g0xbh4-0 lhTYNA"><svg aria-hidden="true" focusable="false" class="octicon octicon-git-branch" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" style="display:inline-block;user-select:none;vertical-align:text-bottom;overflow:visible"><path d="M9.5 3.25a2.25 2.25 0 1 1 3 2.122V6A2.5 2.5 0 0 1 10 8.5H6a1 1 0 0 0-1 1v1.128a2.251 2.251 0 1 1-1.5 0V5.372a2.25 2.25 0 1 1 1.5 0v1.836A2.493 2.493 0 0 1 6 7h4a1 1 0 0 0 1-1v-.628A2.25 2.25 0 0 1 9.5 3.25Zm-6 0a.75.75 0 1 0 1.5 0 .75.75 0 0 0-1.5 0Zm8.25-.75a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5ZM4.25 12a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Z"></path></svg></div><div class="Box-sc-g0xbh4-0 dbrgmi ref-selector-button-text-container"><span class="Text__StyledText-sc-17v1xeu-0 eMMFM"> <!-- -->master</span></div></div></span><span data-component="trailingVisual" class="prc-Button-Visual-2epfX prc-Button-VisualWrap-Db-eB"><svg aria-hidden="true" focusable="false" class="octicon octicon-triangle-down" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" style="display:inline-block;user-select:none;vertical-align:text-bottom;overflow:visible"><path d="m4.427 7.427 3.396 3.396a.25.25 0 0 0 .354 0l3.396-3.396A.25.25 0 0 0 11.396 7H4.604a.25.25 0 0 0-.177.427Z"></path></svg></span></span></button><button hidden="" data-hotkey-scope="read-only-cursor-text-area"></button></div><div class="Box-sc-g0xbh4-0 kGqOLL"><div class="Box-sc-g0xbh4-0 fHind"><nav data-testid="breadcrumbs" aria-labelledby="sticky-breadcrumb-heading" id="sticky-breadcrumb" class="Box-sc-g0xbh4-0 fzFXnm"><h2 class="sr-only ScreenReaderHeading-module__userSelectNone--vW4Cq prc-Heading-Heading-6CmGO" data-testid="screen-reader-heading" id="sticky-breadcrumb-heading">Breadcrumbs</h2><ol class="Box-sc-g0xbh4-0 iMnkmv"><li class="Box-sc-g0xbh4-0 ghzDag"><a class="Box-sc-g0xbh4-0 kHuKdh prc-Link-Link-85e08" sx="[object Object]" data-testid="breadcrumbs-repo-link" href="/google/cel-spec/tree/master">cel-spec</a></li><li class="Box-sc-g0xbh4-0 ghzDag"><span class="Text__StyledText-sc-17v1xeu-0 lauzFl" aria-hidden="true">/</span><a class="Box-sc-g0xbh4-0 kgiVEz prc-Link-Link-85e08" sx="[object Object]" href="/google/cel-spec/tree/master/doc">doc</a></li></ol></nav><div data-testid="breadcrumbs-filename" class="Box-sc-g0xbh4-0 ghzDag"><span class="Text__StyledText-sc-17v1xeu-0 lauzFl" aria-hidden="true">/</span><h1 class="Box-sc-g0xbh4-0 dnZoUW prc-Heading-Heading-6CmGO" tabindex="-1" id="sticky-file-name-id">langdef.md</h1></div></div></div></div><button style="--button-color:fg.default" type="button" class="Box-sc-g0xbh4-0 jRZWlf prc-Button-ButtonBase-c50BI" data-loading="false" data-size="small" data-variant="invisible" aria-describedby=":Riptal9lab:-loading-announcement"><span data-component="buttonContent" class="Box-sc-g0xbh4-0 gUkoLg prc-Button-ButtonContent-HKbr-"><span data-component="leadingVisual" class="prc-Button-Visual-2epfX prc-Button-VisualWrap-Db-eB"><svg aria-hidden="true" focusable="false" class="octicon octicon-arrow-up" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" style="display:inline-block;user-select:none;vertical-align:text-bottom;overflow:visible"><path d="M3.47 7.78a.75.75 0 0 1 0-1.06l4.25-4.25a.75.75 0 0 1 1.06 0l4.25 4.25a.751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018L9 4.81v7.44a.75.75 0 0 1-1.5 0V4.81L4.53 7.78a.75.75 0 0 1-1.06 0Z"></path></svg></span><span data-component="text" class="prc-Button-Label-pTQ3x">Top</span></span></button></div></div></div><div class="Box-sc-g0xbh4-0 kTvpNk"><h2 class="sr-only ScreenReaderHeading-module__userSelectNone--vW4Cq prc-Heading-Heading-6CmGO" data-testid="screen-reader-heading">File metadata and controls</h2><div class="Box-sc-g0xbh4-0 iNMjfP"><ul aria-label="File view" class="SegmentedControl__SegmentedControlList-sc-1rzig82-0 lawgDG" data-size="small"><li class="Box-sc-g0xbh4-0 fefCSX" data-selected="true"><button aria-current="true" class="SegmentedControlButton__SegmentedControlButtonStyled-sc-8lkgxl-0 dwImxt" type="button"><span class="segmentedControl-content"><div class="Box-sc-g0xbh4-0 segmentedControl-text" data-text="Preview">Preview</div></span></button></li><li class="Box-sc-g0xbh4-0 idgUkN"><button aria-current="false" class="SegmentedControlButton__SegmentedControlButtonStyled-sc-8lkgxl-0 iFTkun" type="button"><span class="segmentedControl-content"><div class="Box-sc-g0xbh4-0 segmentedControl-text" data-text="Code">Code</div></span></button></li><li class="Box-sc-g0xbh4-0 idgUkN"><button aria-current="false" class="SegmentedControlButton__SegmentedControlButtonStyled-sc-8lkgxl-0 bHmvop" type="button"><span class="segmentedControl-content"><div class="Box-sc-g0xbh4-0 segmentedControl-text" data-text="Blame">Blame</div></span></button></li></ul><button hidden="" data-testid="" data-hotkey-scope="read-only-cursor-text-area"></button><button hidden="" data-testid="" data-hotkey-scope="read-only-cursor-text-area"></button><button hidden="" data-testid="" data-hotkey-scope="read-only-cursor-text-area"></button><div class="Box-sc-g0xbh4-0 jNEwzY react-code-size-details-in-header"><div class="Box-sc-g0xbh4-0 bsDwxw text-mono"><div title="79.4 KB" data-testid="blob-size" class="Truncate__StyledTruncate-sc-23o1d2-0 eAtkQz"><span>2208 lines (1698 loc) · 79.4 KB</span></div></div></div></div><div class="Box-sc-g0xbh4-0 kcLCKF"><div class="Box-sc-g0xbh4-0 kVWtTz react-blob-header-edit-and-raw-actions"><div class="Box-sc-g0xbh4-0 prc-ButtonGroup-ButtonGroup-vcMeG"><div><a href="https://github.com/google/cel-spec/raw/refs/heads/master/doc/langdef.md" data-testid="raw-button" class="Box-sc-g0xbh4-0 gWqxTd prc-Button-ButtonBase-c50BI" data-loading="false" data-no-visuals="true" data-size="small" data-variant="default" aria-describedby=":R5csptal9lab:-loading-announcement"><span data-component="buttonContent" class="Box-sc-g0xbh4-0 gUkoLg prc-Button-ButtonContent-HKbr-"><span data-component="text" class="prc-Button-Label-pTQ3x">Raw</span></span></a></div><div><button data-component="IconButton" type="button" aria-label="Copy raw content" data-testid="copy-raw-button" class="prc-Button-ButtonBase-c50BI prc-Button-IconButton-szpyj" data-loading="false" data-no-visuals="true" data-size="small" data-variant="default" aria-describedby=":Rpcsptal9lab:-loading-announcement"><svg aria-hidden="true" focusable="false" class="octicon octicon-copy" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" style="display:inline-block;user-select:none;vertical-align:text-bottom;overflow:visible"><path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path><path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path></svg></button></div><div><span role="tooltip" aria-label="Download raw file" id=":Rdcsptal9lab:" class="Tooltip__TooltipBase-sc-17tf59c-0 hWlpPn tooltipped-n"><button data-component="IconButton" type="button" aria-label="Download raw content" data-testid="download-raw-button" class="Box-sc-g0xbh4-0 ivobqY prc-Button-ButtonBase-c50BI prc-Button-IconButton-szpyj" data-loading="false" data-no-visuals="true" data-size="small" data-variant="default" aria-describedby=":Rtcsptal9lab:-loading-announcement"><svg aria-hidden="true" focusable="false" class="octicon octicon-download" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" style="display:inline-block;user-select:none;vertical-align:text-bottom;overflow:visible"><path d="M2.75 14A1.75 1.75 0 0 1 1 12.25v-2.5a.75.75 0 0 1 1.5 0v2.5c0 .138.112.25.25.25h10.5a.25.25 0 0 0 .25-.25v-2.5a.75.75 0 0 1 1.5 0v2.5A1.75 1.75 0 0 1 13.25 14Z"></path><path d="M7.25 7.689V2a.75.75 0 0 1 1.5 0v5.689l1.97-1.969a.749.749 0 1 1 1.06 1.06l-3.25 3.25a.749.749 0 0 1-1.06 0L4.22 6.78a.749.749 0 1 1 1.06-1.06l1.97 1.969Z"></path></svg></button></span></div></div><button hidden="" data-testid="raw-button-shortcut" data-hotkey-scope="read-only-cursor-text-area"></button><button hidden="" data-testid="copy-raw-button-shortcut" data-hotkey-scope="read-only-cursor-text-area"></button><button hidden="" data-testid="download-raw-button-shortcut" data-hotkey-scope="read-only-cursor-text-area"></button></div><button data-component="IconButton" type="button" aria-label="Outline" aria-pressed="false" class="Box-sc-g0xbh4-0 iNRSob prc-Button-ButtonBase-c50BI prc-Button-IconButton-szpyj" data-loading="false" data-no-visuals="true" data-size="small" data-variant="invisible" aria-describedby=":R6sptal9lab:-loading-announcement"><svg aria-hidden="true" focusable="false" class="octicon octicon-list-unordered" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" style="display:inline-block;user-select:none;vertical-align:text-bottom;overflow:visible"><path d="M5.75 2.5h8.5a.75.75 0 0 1 0 1.5h-8.5a.75.75 0 0 1 0-1.5Zm0 5h8.5a.75.75 0 0 1 0 1.5h-8.5a.75.75 0 0 1 0-1.5Zm0 5h8.5a.75.75 0 0 1 0 1.5h-8.5a.75.75 0 0 1 0-1.5ZM2 14a1 1 0 1 1 0-2 1 1 0 0 1 0 2Zm1-6a1 1 0 1 1-2 0 1 1 0 0 1 2 0ZM2 4a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path></svg></button><div class="react-blob-header-edit-and-raw-actions-combined"><button data-component="IconButton" type="button" aria-label="Edit and raw actions" title="More file actions" data-testid="more-file-actions-button" aria-haspopup="true" aria-expanded="false" tabindex="0" class="Box-sc-g0xbh4-0 ffkqe prc-Button-ButtonBase-c50BI js-blob-dropdown-click prc-Button-IconButton-szpyj" data-loading="false" data-no-visuals="true" data-size="small" data-variant="invisible" aria-describedby=":Rnsptal9lab:-loading-announcement" id=":Rnsptal9lab:"><svg aria-hidden="true" focusable="false" class="octicon octicon-kebab-horizontal" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" style="display:inline-block;user-select:none;vertical-align:text-bottom;overflow:visible"><path d="M8 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3ZM1.5 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Zm13 0a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"></path></svg></button></div></div></div></div><div></div></div><div class="Box-sc-g0xbh4-0 hGyMdv"><section aria-labelledby="file-name-id-wide file-name-id-mobile" class="Box-sc-g0xbh4-0 fGqKFv"><div class="Box-sc-g0xbh4-0 eoaCFS js-snippet-clipboard-copy-unpositioned undefined" data-hpc="true"><article class="markdown-body entry-content container-lg" itemprop="text"><div class="markdown-heading" dir="auto"><h1 tabindex="-1" class="heading-element" dir="auto">Language Definition</h1><a id="user-content-language-definition" class="anchor" aria-label="Permalink: Language Definition" href="#language-definition"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">This page constitutes the reference for CEL. For a gentle introduction, see <a href="/google/cel-spec/blob/master/doc/intro.md">Intro</a>.</p> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Contents</h2><a id="user-content-contents" class="anchor" aria-label="Permalink: Contents" href="#contents"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <ul dir="auto"> <li><a href="#overview">Overview</a></li> <li><a href="#syntax">Syntax</a> <ul dir="auto"> <li><a href="#name-resolution">Name Resolution</a></li> </ul> </li> <li><a href="#values">Values</a> <ul dir="auto"> <li><a href="#numeric-values">Numeric Values</a></li> <li><a href="#string-and-bytes-values">String and Bytes Values</a></li> <li><a href="#aggregate-values">Aggregate Values</a></li> <li><a href="#booleans-and-null">Booleans and Null</a></li> <li><a href="#type-values">Type Values</a></li> <li><a href="#abstract-types">Abstract Types</a></li> <li><a href="#protocol-buffer-data-conversion">Protocol Buffer Data Conversion</a></li> <li><a href="#dynamic-values">Dynamic Values</a></li> </ul> </li> <li><a href="#json-data-conversion">JSON Data Conversion</a></li> <li><a href="#gradual-type-checking">Gradual Type Checking</a></li> <li><a href="#evaluation">Evaluation</a> <ul dir="auto"> <li><a href="#evaluation-environment">Evaluation Environment</a></li> <li><a href="#runtime-errors">Runtime Errors</a></li> <li><a href="#logical-operators">Logical Operators</a></li> <li><a href="#macros">Macros</a></li> <li><a href="#field-selection">Field Selection</a></li> </ul> </li> <li><a href="#performance">Performance</a> <ul dir="auto"> <li><a href="#abstract-sizes">Abstract Sizes</a></li> <li><a href="#time-complexity">Time Complexity</a></li> <li><a href="#space-complexity">Space Complexity</a></li> <li><a href="#macro-performance">Macro Performance</a></li> <li><a href="#performance-limits">Performance Limits</a></li> </ul> </li> <li><a href="#functions">Functions</a> <ul dir="auto"> <li><a href="#extension-functions">Extension Functions</a></li> <li><a href="#receiver-call-style">Receiver Call Style</a></li> </ul> </li> <li><a href="#standard-definitions">Standard Definitions</a> <ul dir="auto"> <li><a href="#equality">Equality</a></li> <li><a href="#ordering">Ordering</a></li> <li><a href="#overflow">Overflow</a></li> <li><a href="#timezones">Timezones</a></li> <li><a href="#regular-expressions">Regular Expressions</a></li> <li><a href="#standard-environment">Standard Environment</a></li> </ul> </li> <li><a href="#appendix-1-legacy-behavior">Appendix 1: Legacy Behavior</a> <ul dir="auto"> <li><a href="#enums-as-ints">Enums as Ints</a></li> </ul> </li> </ul> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Overview</h2><a id="user-content-overview" class="anchor" aria-label="Permalink: Overview" href="#overview"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">In the taxonomy of programming languages, CEL is:</p> <ul dir="auto"> <li><strong>memory-safe:</strong> programs cannot access unrelated memory, such as out-of-bounds array indexes or use-after-free pointer dereferences;</li> <li><strong>side-effect-free:</strong> a CEL program only computes an output from its inputs;</li> <li><strong>terminating:</strong> CEL programs cannot loop forever;</li> <li><strong>strongly-typed:</strong> values have a well-defined type, and operators and functions check that their arguments have the expected types;</li> <li><strong>dynamically-typed:</strong> types are associated with values, not with variables or expressions, and type safety is enforced at runtime;</li> <li><strong>gradually-typed:</strong> an optional type-checking phase before runtime can detect and reject some programs which would violate type constraints.</li> </ul> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Syntax</h2><a id="user-content-syntax" class="anchor" aria-label="Permalink: Syntax" href="#syntax"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">The grammar of CEL is defined below, using <code>|</code> for alternatives, <code>[]</code> for optional, <code>{}</code> for repeated, and <code>()</code> for grouping.</p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="Expr = ConditionalOr [&quot;?&quot; ConditionalOr &quot;:&quot; Expr] ; ConditionalOr = [ConditionalOr &quot;||&quot;] ConditionalAnd ; ConditionalAnd = [ConditionalAnd &quot;&amp;&amp;&quot;] Relation ; Relation = [Relation Relop] Addition ; Relop = &quot;&lt;&quot; | &quot;&lt;=&quot; | &quot;&gt;=&quot; | &quot;&gt;&quot; | &quot;==&quot; | &quot;!=&quot; | &quot;in&quot; ; Addition = [Addition (&quot;+&quot; | &quot;-&quot;)] Multiplication ; Multiplication = [Multiplication (&quot;*&quot; | &quot;/&quot; | &quot;%&quot;)] Unary ; Unary = Member | &quot;!&quot; {&quot;!&quot;} Member | &quot;-&quot; {&quot;-&quot;} Member ; Member = Primary | Member &quot;.&quot; IDENT [&quot;(&quot; [ExprList] &quot;)&quot;] | Member &quot;[&quot; Expr &quot;]&quot; ; Primary = [&quot;.&quot;] IDENT [&quot;(&quot; [ExprList] &quot;)&quot;] | &quot;(&quot; Expr &quot;)&quot; | &quot;[&quot; [ExprList] [&quot;,&quot;] &quot;]&quot; | &quot;{&quot; [MapInits] [&quot;,&quot;] &quot;}&quot; | [&quot;.&quot;] IDENT { &quot;.&quot; IDENT } &quot;{&quot; [FieldInits] [&quot;,&quot;] &quot;}&quot; | LITERAL ; ExprList = Expr {&quot;,&quot; Expr} ; FieldInits = IDENT &quot;:&quot; Expr {&quot;,&quot; IDENT &quot;:&quot; Expr} ; MapInits = Expr &quot;:&quot; Expr {&quot;,&quot; Expr &quot;:&quot; Expr} ;"><pre lang="grammar" class="notranslate"><code>Expr = ConditionalOr ["?" ConditionalOr ":" Expr] ; ConditionalOr = [ConditionalOr "||"] ConditionalAnd ; ConditionalAnd = [ConditionalAnd "&amp;&amp;"] Relation ; Relation = [Relation Relop] Addition ; Relop = "&lt;" | "&lt;=" | "&gt;=" | "&gt;" | "==" | "!=" | "in" ; Addition = [Addition ("+" | "-")] Multiplication ; Multiplication = [Multiplication ("*" | "/" | "%")] Unary ; Unary = Member | "!" {"!"} Member | "-" {"-"} Member ; Member = Primary | Member "." IDENT ["(" [ExprList] ")"] | Member "[" Expr "]" ; Primary = ["."] IDENT ["(" [ExprList] ")"] | "(" Expr ")" | "[" [ExprList] [","] "]" | "{" [MapInits] [","] "}" | ["."] IDENT { "." IDENT } "{" [FieldInits] [","] "}" | LITERAL ; ExprList = Expr {"," Expr} ; FieldInits = IDENT ":" Expr {"," IDENT ":" Expr} ; MapInits = Expr ":" Expr {"," Expr ":" Expr} ; </code></pre></div> <p dir="auto">Implementations are required to support at least:</p> <ul dir="auto"> <li>24-32 repetitions of repeating rules, i.e.: <ul dir="auto"> <li>32 terms separated by <code>||</code> in a row;</li> <li>32 terms separated by <code>&amp;&amp;</code> in a row;</li> <li>32 function call arguments;</li> <li>list literals with 32 elements;</li> <li>map or message literals with 32 fields;</li> <li>24 consecutive ternary conditionals <code>?:</code>;</li> <li>24 binary arithmetic operators of the same precedence in a row;</li> <li>24 relations in a row.</li> </ul> </li> <li>12 repetitions of recursive rules, i.e: <ul dir="auto"> <li>12 nested function calls;</li> <li>12 selection (<code>.</code>) operators in a row;</li> <li>12 indexing (<code>[_]</code>) operators in a row;</li> <li>12 nested list, map, or message literals.</li> </ul> </li> </ul> <p dir="auto">This grammar corresponds to the following operator precedence and associativity:</p> <markdown-accessiblity-table><table> <thead> <tr> <th>Precedence</th> <th>Operator</th> <th>Description</th> <th>Associativity</th> </tr> </thead> <tbody> <tr> <td>1</td> <td>()</td> <td>Function call</td> <td>Left-to-right</td> </tr> <tr> <td> </td> <td>.</td> <td>Qualified name or field access</td> <td></td> </tr> <tr> <td> </td> <td>[]</td> <td>Indexing</td> <td></td> </tr> <tr> <td> </td> <td>{}</td> <td>Field initialization</td> <td></td> </tr> <tr> <td>2</td> <td>- (unary)</td> <td>Negation</td> <td>Right-to-left</td> </tr> <tr> <td> </td> <td>!</td> <td>Logical NOT</td> <td></td> </tr> <tr> <td>3</td> <td>*</td> <td>Multiplication</td> <td>Left-to-right</td> </tr> <tr> <td> </td> <td>/</td> <td>Division</td> <td></td> </tr> <tr> <td> </td> <td>%</td> <td>Remainder</td> <td></td> </tr> <tr> <td>4</td> <td>+</td> <td>Addition</td> <td></td> </tr> <tr> <td> </td> <td>- (binary)</td> <td>Subtraction</td> <td></td> </tr> <tr> <td>5</td> <td>== != &lt; &gt; &lt;= &gt;=</td> <td>Relations</td> <td></td> </tr> <tr> <td> </td> <td>in</td> <td>Inclusion test</td> <td></td> </tr> <tr> <td>6</td> <td>&amp;&amp;</td> <td>Logical AND</td> <td></td> </tr> <tr> <td>7</td> <td>||</td> <td>Logical OR</td> <td></td> </tr> <tr> <td>8</td> <td>?:</td> <td>Conditional</td> <td>Right-to-left</td> </tr> </tbody> </table></markdown-accessiblity-table> <p dir="auto">The lexis is defined below. As is typical, the <code>WHITESPACE</code> and <code>COMMENT</code> productions are only used to recognize separate lexical elements and are ignored by the grammar. Please note, that in the lexer <code>[]</code> denotes a character range, <code>*</code> represents zero or more, <code>+</code> represents one or more, and <code>?</code> denotes zero or one occurrence.</p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="IDENT ::= [_a-zA-Z][_a-zA-Z0-9]* - RESERVED LITERAL ::= INT_LIT | UINT_LIT | FLOAT_LIT | STRING_LIT | BYTES_LIT | BOOL_LIT | NULL_LIT INT_LIT ::= -? DIGIT+ | -? 0x HEXDIGIT+ UINT_LIT ::= INT_LIT [uU] FLOAT_LIT ::= -? DIGIT* . DIGIT+ EXPONENT? | -? DIGIT+ EXPONENT DIGIT ::= [0-9] HEXDIGIT ::= [0-9abcdefABCDEF] EXPONENT ::= [eE] [+-]? DIGIT+ STRING_LIT ::= [rR]? ( &quot; ~( &quot; | \r | \n )* &quot; | ' ~( ' | \r | \n )* ' | &quot;&quot;&quot; ~&quot;&quot;&quot;* &quot;&quot;&quot; | ''' ~'''* ''' ) BYTES_LIT ::= [bB] STRING_LIT ESCAPE ::= \ [abfnrtv\?&quot;'`] | \ [xX] HEXDIGIT HEXDIGIT | \ u HEXDIGIT HEXDIGIT HEXDIGIT HEXDIGIT | \ U HEXDIGIT HEXDIGIT HEXDIGIT HEXDIGIT HEXDIGIT HEXDIGIT HEXDIGIT HEXDIGIT | \ [0-3] [0-7] [0-7] BOOL_LIT ::= &quot;true&quot; | &quot;false&quot; NULL_LIT ::= &quot;null&quot; RESERVED ::= BOOL_LIT | NULL_LIT | &quot;in&quot; | &quot;as&quot; | &quot;break&quot; | &quot;const&quot; | &quot;continue&quot; | &quot;else&quot; | &quot;for&quot; | &quot;function&quot; | &quot;if&quot; | &quot;import&quot; | &quot;let&quot; | &quot;loop&quot; | &quot;package&quot; | &quot;namespace&quot; | &quot;return&quot; | &quot;var&quot; | &quot;void&quot; | &quot;while&quot; WHITESPACE ::= [\t\n\f\r ]+ COMMENT ::= '//' ~\n* \n"><pre class="notranslate"><code>IDENT ::= [_a-zA-Z][_a-zA-Z0-9]* - RESERVED LITERAL ::= INT_LIT | UINT_LIT | FLOAT_LIT | STRING_LIT | BYTES_LIT | BOOL_LIT | NULL_LIT INT_LIT ::= -? DIGIT+ | -? 0x HEXDIGIT+ UINT_LIT ::= INT_LIT [uU] FLOAT_LIT ::= -? DIGIT* . DIGIT+ EXPONENT? | -? DIGIT+ EXPONENT DIGIT ::= [0-9] HEXDIGIT ::= [0-9abcdefABCDEF] EXPONENT ::= [eE] [+-]? DIGIT+ STRING_LIT ::= [rR]? ( " ~( " | \r | \n )* " | ' ~( ' | \r | \n )* ' | """ ~"""* """ | ''' ~'''* ''' ) BYTES_LIT ::= [bB] STRING_LIT ESCAPE ::= \ [abfnrtv\?"'`] | \ [xX] HEXDIGIT HEXDIGIT | \ u HEXDIGIT HEXDIGIT HEXDIGIT HEXDIGIT | \ U HEXDIGIT HEXDIGIT HEXDIGIT HEXDIGIT HEXDIGIT HEXDIGIT HEXDIGIT HEXDIGIT | \ [0-3] [0-7] [0-7] BOOL_LIT ::= "true" | "false" NULL_LIT ::= "null" RESERVED ::= BOOL_LIT | NULL_LIT | "in" | "as" | "break" | "const" | "continue" | "else" | "for" | "function" | "if" | "import" | "let" | "loop" | "package" | "namespace" | "return" | "var" | "void" | "while" WHITESPACE ::= [\t\n\f\r ]+ COMMENT ::= '//' ~\n* \n </code></pre></div> <p dir="auto">For the sake of a readable representation, the escape sequences (<code>ESCAPE</code>) are kept implicit in string tokens. This means that strings without the <code>r</code> or <code>R</code> (raw) prefix process <code>ESCAPE</code> sequences, while in strings with the raw prefix they stay uninterpreted. See documentation of string literals below.</p> <p dir="auto">The following identifiers are reserved due to their use as literal values or in the syntax:</p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="false in null true"><pre class="notranslate"><code>false in null true </code></pre></div> <p dir="auto">The following identifiers are reserved to allow easier embedding of CEL into a host language.</p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="as break const continue else for function if import let loop package namespace return var void while"><pre class="notranslate"><code>as break const continue else for function if import let loop package namespace return var void while </code></pre></div> <p dir="auto">In general it is a bad idea for those defining contexts or extensions to use identifiers that are reserved words in programming languages which might embed CEL.</p> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Name Resolution</h3><a id="user-content-name-resolution" class="anchor" aria-label="Permalink: Name Resolution" href="#name-resolution"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">A CEL expression is parsed in the scope of a specific protocol buffer package or message, which controls the interpretation of names. The scope is set by the application context of an expression. A CEL expression can contain simple names as in <code>a</code> or qualified names as in <code>a.b</code>. The meaning of such expressions is a combination of one or more of:</p> <ul dir="auto"> <li>Variables and Functions: some simple names refer to variables in the execution context, standard functions, or other name bindings provided by the CEL application.</li> <li>Field selection: appending a period and identifier to an expression could indicate that we're accessing a field within a protocol buffer or map.</li> <li>Protocol buffer package names: a simple or qualified name could represent an absolute or relative name in the protocol buffer package namespace. Package names must be followed by a message type, or enum constant.</li> <li>Protocol buffer message types and enum constants: following an optional protocol buffer package name, a simple or qualified name could refer to a message type or an enum constant in the package's namespace.</li> </ul> <p dir="auto">Resolution works as follows. If <code>a.b</code> is a name to be resolved in the context of a protobuf declaration with scope <code>A.B</code>, then resolution is attempted, in order, as <code>A.B.a.b</code>, <code>A.a.b</code>, and finally <code>a.b</code>. To override this behavior, one can use <code>.a.b</code>; this name will only be attempted to be resolved in the root scope, i.e. as <code>a.b</code>.</p> <p dir="auto">If name qualification is mixed with field selection, the longest prefix of the name which resolves in the current lexical scope is used. For example, if <code>a.b.c</code> resolves to a message declaration, and <code>a.b</code> does so as well with <code>c</code> a possible field selection, then <code>a.b.c</code> takes priority over the interpretation <code>(a.b).c</code>.</p> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Values</h2><a id="user-content-values" class="anchor" aria-label="Permalink: Values" href="#values"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Values in CEL represent any of the following:</p> <markdown-accessiblity-table><table> <thead> <tr> <th>Type</th> <th>Description</th> </tr> </thead> <tbody> <tr> <td><code>int</code></td> <td>64-bit signed integers</td> </tr> <tr> <td><code>uint</code></td> <td>64-bit unsigned integers</td> </tr> <tr> <td><code>double</code></td> <td>64-bit IEEE floating-point numbers</td> </tr> <tr> <td><code>bool</code></td> <td>Booleans (<code>true</code> or <code>false</code>)</td> </tr> <tr> <td><code>string</code></td> <td>Strings of Unicode code points</td> </tr> <tr> <td><code>bytes</code></td> <td>Byte sequences</td> </tr> <tr> <td><code>list</code></td> <td>Lists of values</td> </tr> <tr> <td><code>map</code></td> <td>Associative arrays with <code>int</code>, <code>uint</code>, <code>bool</code>, or <code>string</code> keys</td> </tr> <tr> <td><code>null_type</code></td> <td>The value <code>null</code></td> </tr> <tr> <td>message names</td> <td>Protocol buffer messages</td> </tr> <tr> <td><code>type</code></td> <td>Values representing the types in the first column</td> </tr> </tbody> </table></markdown-accessiblity-table> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Numeric Values</h3><a id="user-content-numeric-values" class="anchor" aria-label="Permalink: Numeric Values" href="#numeric-values"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">CEL supports only 64-bit integers and 64-bit IEEE double-precision floating-point. We only support positive, decimal integer literals; negative integers are produced by the unary negation operator. Note that the integer 7 as an <code>int</code> is a different value than 7 as a <code>uint</code>, which would be written <code>7u</code>. Double-precision floating-point is also supported, and the integer 7 would be written <code>7.0</code>, <code>7e0</code>, <code>.700e1</code>, or any equivalent representation using a decimal point or exponent.</p> <p dir="auto">Note that currently there are no automatic arithmetic conversions for the numeric types (<code>int</code>, <code>uint</code>, and <code>double</code>). The arithmetic operators typically contain overloads for arguments of the same numeric type, but not for mixed-type arguments. Therefore an expression like <code>1 + 1u</code> is going to fail to dispatch. To perform mixed-type arithmetic, use explicit conversion functions such as <code>uint(1) + 1u</code>. Such explicit conversions will maintain their meaning even if arithmetic conversions are added in the future.</p> <p dir="auto">CEL provides no way to control the finer points of floating-point arithmetic, such as expression evaluation, rounding mode, or exception handling. However, any two not-a-number values will compare equal even if their underlying properties are different.</p> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">String and Bytes Values</h3><a id="user-content-string-and-bytes-values" class="anchor" aria-label="Permalink: String and Bytes Values" href="#string-and-bytes-values"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Strings are valid sequences of Unicode code points. Bytes are arbitrary sequences of octets (eight-bit data).</p> <p dir="auto">Quoted string literals are delimited by either single- or double-quote characters, where the closing delimiter must match the opening one, and can contain any unescaped character except the delimiter or newlines (either CR or LF).</p> <p dir="auto">Triple-quoted string literals are delimited by three single-quotes or three double-quotes, and may contain any unescaped characters except for the delimiter sequence. Again, the closing delimiter must match the opening one. Triple-quoted strings may contain newlines.</p> <p dir="auto">Both sorts of strings can include escape sequences, described below.</p> <p dir="auto">If preceded by an <code>r</code> or <code>R</code> character, the string is a <em>raw</em> string and does not interpret escape sequences. Raw strings are useful for expressing strings which themselves must use escape sequences, such as regular expressions or program text.</p> <p dir="auto">Bytes literals are represented by string literals preceded by a <code>b</code> or <code>B</code> character. The bytes literal is the sequence of bytes given by the UTF-8 representation of the string literal. In addition, the octal escape sequence are interpreted as octet values rather than as Unicode code points. Both raw and multiline string literals can be used for byte literals.</p> <p dir="auto">Escape sequences are a backslash (<code>\</code>) followed by one of the following:</p> <ul dir="auto"> <li>A punctuation mark representing itself: <ul dir="auto"> <li><code>\</code>: backslash</li> <li><code>?</code>: question mark</li> <li><code>"</code>: double quote</li> <li><code>'</code>: single quote</li> <li><code>`</code>: backtick</li> </ul> </li> <li>A code for whitespace: <ul dir="auto"> <li><code>a</code>: bell</li> <li><code>b</code>: backspace</li> <li><code>f</code>: form feed</li> <li><code>n</code>: line feed</li> <li><code>r</code>: carriage return</li> <li><code>t</code>: horizontal tab</li> <li><code>v</code>: vertical tab</li> </ul> </li> <li>A <code>u</code> followed by four hexadecimal characters, encoding a Unicode code point in the <a href="https://www.unicode.org/roadmaps/bmp/" rel="nofollow">BMP</a>.</li> <li>A <code>U</code> followed by eight hexadecimal characters, encoding a Unicode code point (in any plane). Valid only for string literals.</li> <li>A <code>x</code> or <code>X</code> followed by two hexadecimal characters. For strings, it denotes a Unicode code point. For bytes, it represents an octet value.</li> <li>Three octal digits, in the range <code>000</code> to <code>377</code>. For strings, it denotes a Unicode code point. For bytes, it represents an octet value.</li> </ul> <p dir="auto">All hexadecimal digits in escape sequences are case-insensitive.</p> <p dir="auto">Examples:</p> <markdown-accessiblity-table><table> <thead> <tr> <th>CEL Literal</th> <th>Meaning</th> </tr> </thead> <tbody> <tr> <td><code>""</code></td> <td>Empty string</td> </tr> <tr> <td><code>'""'</code></td> <td>String of two double-quote characters</td> </tr> <tr> <td><code>'''x''x'''</code></td> <td>String of four characters "<code>x''x</code>"</td> </tr> <tr> <td><code>"\""</code></td> <td>String of one double-quote character</td> </tr> <tr> <td><code>"\\"</code></td> <td>String of one backslash character</td> </tr> <tr> <td><code>r"\\"</code></td> <td>String of two backslash characters</td> </tr> <tr> <td><code>b"abc"</code></td> <td>Byte sequence of 97, 98, 99</td> </tr> <tr> <td><code>b"ÿ"</code></td> <td>Sequence of bytes 195 and 191 (UTF-8 of ÿ)</td> </tr> <tr> <td><code>b"\303\277"</code></td> <td>Also sequence of bytes 195 and 191</td> </tr> <tr> <td><code>"\303\277"</code></td> <td>String of "ÿ" (code points 195, 191)</td> </tr> <tr> <td><code>"\377"</code></td> <td>String of "ÿ" (code point 255)</td> </tr> <tr> <td><code>b"\377"</code></td> <td>Sequence of byte 255 (<em>not</em> UTF-8 of ÿ)</td> </tr> <tr> <td><code>"\xFF"</code></td> <td>String of "ÿ" (code point 255)</td> </tr> <tr> <td><code>b"\xff"</code></td> <td>Sequence of byte 255 (<em>not</em> UTF-8 of ÿ)</td> </tr> </tbody> </table></markdown-accessiblity-table> <p dir="auto">The following constructions are syntactically invalid and will result in a parse error:</p> <ul dir="auto"> <li>A backslash (<code>\</code>) outside of a valid escape sequence, e.g. <code>\s</code>.</li> <li>An invalid Unicode code point, e.g. <code>\u2FE0</code>.</li> <li>A UTF-16 surrogate code point, even if in a valid UTF-16 surrogate pair, e.g. <code>\uD83D\uDE03</code> or <code>\UD83DDE03</code>.</li> </ul> <p dir="auto">While strings must be sequences of valid Unicode code points, no Unicode normalization is attempted on strings, as there are several normal forms, they can be expensive to convert, and we don't know which is desired. If Unicode normalization is desired, it should be performed outside of CEL, or done as a custom extension function.</p> <p dir="auto">Likewise, no advanced collation is attempted on strings, as this depends on the normalization and can be locale-dependent. Strings are simply treated as sequences of code points and are ordered with lexicographic ordering based on the numeric value of the code points.</p> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Aggregate Values</h3><a id="user-content-aggregate-values" class="anchor" aria-label="Permalink: Aggregate Values" href="#aggregate-values"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Lists are ordered sequences of values.</p> <p dir="auto">Maps are a set of key values, and a mapping from these keys to arbitrary values. Key values must be an allowed key type: <code>int</code>, <code>uint</code>, <code>bool</code>, or <code>string</code>. Thus maps are the union of what's allowed in protocol buffer maps and JSON objects.</p> <p dir="auto">Note that the type checker uses a finer-grained notion of list and map types. Lists are <code>list(A)</code> for the homogeneous type <code>A</code> of list elements. Maps are <code>map(K, V)</code> for maps with keys of type <code>K</code> and values of type <code>V</code>. The type <code>dyn</code> is used for heterogeneous values See <a href="#gradual-type-checking">Gradual Type Checking</a>. But these constraints are only enforced within the type checker; at runtime, lists and maps can have heterogeneous types.</p> <p dir="auto">Any protocol buffer message is a CEL value, and each message type is its own CEL type, represented as its fully-qualified name.</p> <p dir="auto">A list can be denoted by the expression <code>[e1, e2, ..., eN]</code>, a map by <code>{ek1: ev1, ek2: ev2, ..., ekN: evN}</code>, and a message by <code>M{f1: e1, f2: e2, ..., fN: eN}</code>, where <code>M</code> must be a simple or qualified name which resolves to a message type (see <a href="#name-resolution">Name Resolution</a>). For a map, the entry keys are sub-expressions that must evaluate to values of an allowed type (<code>int</code>, <code>uint</code>, <code>bool</code>, or <code>string</code>). For a message, the field names are identifiers. It is an error to have duplicate keys or field names. The empty list, map, and message are <code>[]</code>, <code>{}</code>, and <code>M{}</code>, respectively.</p> <p dir="auto">See <a href="#field-selection">Field Selection</a> for accessing elements of lists, maps, and messages.</p> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Booleans and Null</h3><a id="user-content-booleans-and-null" class="anchor" aria-label="Permalink: Booleans and Null" href="#booleans-and-null"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">CEL has <code>true</code> and <code>false</code> as the literals for the <code>bool</code> type, with the usual meanings.</p> <p dir="auto">The null value is written <code>null</code>. It is used in conversion to and from protocol buffer and JSON data, but otherwise has no built-in meaning in CEL. In particular, null has its own type (<code>null_type</code>) and is not necessarily allowed where a value of some other type is expected.</p> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Type Values</h3><a id="user-content-type-values" class="anchor" aria-label="Permalink: Type Values" href="#type-values"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Every value in CEL has a runtime type which is itself a value. The standard function <code>type(x)</code> returns the type of expression <code>x</code>.</p> <p dir="auto">As types are values, those values (<code>int</code>, <code>string</code>, etc.) also have a type: the type <code>type</code>, which is an expression by itself which in turn also has type <code>type</code>. So</p> <ul dir="auto"> <li><code>type(1)</code> evaluates to <code>int</code></li> <li><code>type("a")</code> evaluates to <code>string</code></li> <li><code>type(1) == string</code> evaluates to <code>false</code></li> <li><code>type(type(1)) == type(string)</code> evaluates to <code>true</code></li> </ul> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Abstract Types</h3><a id="user-content-abstract-types" class="anchor" aria-label="Permalink: Abstract Types" href="#abstract-types"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">A CEL implementation can add new types to the language. These types will be given names in the same namespace as the other types, but will have no special support in the language syntax. The only way to construct or use values of these abstract types is through functions which the implementor must also provide.</p> <p dir="auto">Commonly, an abstract type will have a representation as a protocol buffer, so that it can be stored or transmitted across a network. In this case, the abstract type will be given the same name as the protocol buffer, which will prevent CEL programs from being able to use that particular protocol buffer message type; they will not be able to construct values of that type by message expressions nor access the message fields. The abstract type remains abstract.</p> <p dir="auto">By default, CEL uses <code>google.protobuf.Timestamp</code> and <code>google.protobuf.Duration</code> as abstract types. The standard functions provide ways to construct and manipulate these values, but CEL programs cannot construct them with message expressions or access their message fields.</p> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Protocol Buffer Data Conversion</h3><a id="user-content-protocol-buffer-data-conversion" class="anchor" aria-label="Permalink: Protocol Buffer Data Conversion" href="#protocol-buffer-data-conversion"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Protocol buffers have a richer range of types than CEL, so Protocol buffer data is converted to CEL data when read from a message field, and CEL data is converted in the other direction when initializing a field. In general, protocol buffer data can be converted to CEL without error, but range errors are possible in the other direction.</p> <markdown-accessiblity-table><table> <thead> <tr> <th>Protocol Buffer Field Type</th> <th>CEL Type</th> </tr> </thead> <tbody> <tr> <td>int32, int64, sint32, sint64, sfixed32, sfixed64</td> <td><code>int</code></td> </tr> <tr> <td>uint32, uint64, fixed32, fixed64</td> <td><code>uint</code></td> </tr> <tr> <td>float, double</td> <td><code>double</code></td> </tr> <tr> <td>bool, string, bytes</td> <td>same</td> </tr> <tr> <td>enum E</td> <td><code>int</code></td> </tr> <tr> <td>repeated</td> <td><code>list</code></td> </tr> <tr> <td>map&lt;K, V&gt;</td> <td><code>map</code></td> </tr> <tr> <td>oneof</td> <td>options expanded individually, at most one is set</td> </tr> <tr> <td>message M</td> <td>M, except for conversions below</td> </tr> </tbody> </table></markdown-accessiblity-table> <p dir="auto">Signed integers, unsigned integers, and floating point numbers are converted to the singular CEL type of the same sort. The CEL type is capable of expressing the full range of protocol buffer values. When converting from CEL to protocol buffers, an out-of-range CEL value results in an error.</p> <p dir="auto">Boolean, string, and bytes types have identical ranges and are converted without error.</p> <p dir="auto">Protocol buffer enum values are converted to the corresponding <code>int</code> value. Protocol buffer enum fields can accept any signed 32-bit number, values outside that range will raise an error.</p> <p dir="auto">Repeated fields are converted to CEL lists of converted values, preserving the order. In the other direction, the CEL list elements must be of the right type and value to be converted to the corresponding protocol buffer type. Similarly, protocol buffer maps are converted to CEL maps, and CEL map keys and values must have the right type and value to be converted in the other direction.</p> <p dir="auto">Oneof fields are represented by the translation of each of their options as a separate field, but at most one of these fields will be "set", as detected by the <code>has()</code> macro. See <a href="#macros">Macros</a>.</p> <p dir="auto">Since protocol buffer messages are first-class CEL values, message-valued fields are used without conversion.</p> <p dir="auto">Every protocol buffer field has a default value, and there is no semantic difference between a field set to this default value, and an unset field. For message fields, their default value is just the unset state, and an unset message field is distinct from one set to an empty (i.e. all-unset) message.</p> <p dir="auto">The <code>has()</code> macro (see <a href="#macros">Macros</a>) tells whether a message field is set (i.e. not unset, hence not set to the default value). If an unset field is nevertheless selected, it evaluates to its default value, or if it is a message field, it evaluates to an empty (i.e. all-unset) message. This allows expressions to use iterative field selection to examine the state of fields in deeply nested messages without needing to test whether every intermediate field is set. (See exception for wrapper types, below.)</p> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Dynamic Values</h3><a id="user-content-dynamic-values" class="anchor" aria-label="Permalink: Dynamic Values" href="#dynamic-values"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">CEL automatically converts certain protocol buffer messages in the <code>google.protobuf</code> package to other types.</p> <markdown-accessiblity-table><table> <thead> <tr> <th>google.protobuf message</th> <th>CEL Conversion</th> </tr> </thead> <tbody> <tr> <td><code>Any</code></td> <td>dynamically converted to the contained message type, or error</td> </tr> <tr> <td><code>ListValue</code></td> <td>list of <code>Value</code> messages</td> </tr> <tr> <td><code>Struct</code></td> <td>map (with string keys, <code>Value</code> values)</td> </tr> <tr> <td><code>Value</code></td> <td>dynamically converted to the contained type (null, double, string, bool, <code>Struct</code>, or <code>ListValue</code>)</td> </tr> <tr> <td>wrapper types</td> <td>converted as eponymous field type</td> </tr> </tbody> </table></markdown-accessiblity-table> <p dir="auto">The wrapper types are <code>BoolValue</code>, <code>BytesValue</code>, <code>DoubleValue</code>, <code>FloatValue</code>, <code>Int32Value</code>, <code>Int64Value</code>, <code>NullValue</code>, <code>StringValue</code>, <code>Uint32Value</code>, and <code>Uint64Value</code>. Values of these wrapper types are converted to the obvious type. Additionally, field selection of an unset message field of wrapper type will evaluate to <code>null</code>, instead of the default message. This is an exception to the usual evaluation of unset message fields.</p> <p dir="auto">Note that this implies some cascading conversions. An <code>Any</code> message might be converted to a <code>Struct</code>, one of whose <code>Value</code>-typed values might be converted to a <code>ListValue</code> of more values, and so on.</p> <p dir="auto">Also, note that all of these conversions are dynamic at runtime, so CEL's static type analysis cannot avoid the possibility of type-related errors in expressions using these dynamic values.</p> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">JSON Data Conversion</h2><a id="user-content-json-data-conversion" class="anchor" aria-label="Permalink: JSON Data Conversion" href="#json-data-conversion"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">CEL can also work with JSON data. Since there is a natural correspondence of most CEL data with protocol buffer data, and protocol buffers have a <a href="https://developers.google.com/protocol-buffers/docs/proto3#json" rel="nofollow">defined mapping</a> to JSON, this creates a natural mapping of CEL to JSON. This creates an exact bidirectional mapping between JSON types and a subset of CEL data:</p> <markdown-accessiblity-table><table> <thead> <tr> <th>JSON Type</th> <th>CEL Type</th> </tr> </thead> <tbody> <tr> <td><code>null</code></td> <td><code>null</code></td> </tr> <tr> <td>Boolean</td> <td><code>bool</code></td> </tr> <tr> <td>Number</td> <td><code>double</code> (except infinities or NaN)</td> </tr> <tr> <td>String</td> <td><code>string</code></td> </tr> <tr> <td>Array</td> <td><code>list</code> of bi-convertible elements</td> </tr> <tr> <td>Object</td> <td><code>map</code> (with string keys, bi-convertible values)</td> </tr> </tbody> </table></markdown-accessiblity-table> <p dir="auto">We define JSON mappings for much of the remainder of CEL data, but note that this data will not map back in to CEL as the same value:</p> <markdown-accessiblity-table><table> <thead> <tr> <th>CEL Data</th> <th>JSON Data</th> </tr> </thead> <tbody> <tr> <td><code>int</code></td> <td>Number if in interoperable range, otherwise decimal String.</td> </tr> <tr> <td><code>uint</code></td> <td>Number if in interoperable range, otherwise decimal String.</td> </tr> <tr> <td>double infinity</td> <td>String <code>"Infinity"</code> or <code>"-Infinity"</code></td> </tr> <tr> <td>double NaN</td> <td>String "NaN"</td> </tr> <tr> <td><code>bytes</code></td> <td>String of base64-encoded bytes</td> </tr> <tr> <td>message</td> <td>JSON conversion of protobuf message.</td> </tr> <tr> <td><code>list</code> of convertible elements</td> <td>JSON Array of converted values</td> </tr> <tr> <td><code>list</code> with a non-convertible element</td> <td>none</td> </tr> <tr> <td><code>map</code> with string keys and convertible values</td> <td>JSON Object with converted values</td> </tr> <tr> <td><code>map</code> with a non-string key or a non-convertible value</td> <td>none</td> </tr> <tr> <td><code>type</code></td> <td>none</td> </tr> </tbody> </table></markdown-accessiblity-table> <p dir="auto">The "interoperable" range of integer values is <code>-(2^53-1)</code> to <code>2^53 - 1</code>.</p> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Gradual Type Checking</h2><a id="user-content-gradual-type-checking" class="anchor" aria-label="Permalink: Gradual Type Checking" href="#gradual-type-checking"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">CEL is a dynamically-typed language, meaning that the types of the values of the variables and expressions might not be known until runtime. However, CEL has an optional type-checking phase that takes the types declared for all functions and variables and tries to deduce the type of the expression and of all its sub-expressions. This is not always possible, due to the dynamic expansion of certain messages like <code>Struct</code>, <code>Value</code>, and <code>Any</code> (see <a href="#dynamic-values">Dynamic Values</a>). However, if a CEL program does not use dynamically-expanded messages, it can be statically type-checked.</p> <p dir="auto">The type checker uses a richer type system than the types of the dynamic values: lists have a type parameter for the type of the elements, and maps have two parameters for the types of keys and values, respectively. These richer types preserve the stronger type guarantees that protocol buffer messages have. We can infer stronger types from the standard functions, such as accessing list elements or map fields. However, the <code>type()</code> function and dynamic dispatch to particular function overloads only use the coarser types of the dynamic values.</p> <p dir="auto">The type checker also introduces the <code>dyn</code> type, which is the union of all other types. Therefore the type checker could accept a list of heterogeneous values as <code>dyn([1, 3.14, "foo"])</code>, which is given the type <code>list(dyn)</code>. The standard function <code>dyn</code> has no effect at runtime, but signals to the type checker that its argument should be considered of type <code>dyn</code>, <code>list(dyn)</code>, or a <code>dyn</code>-valued map.</p> <p dir="auto">A CEL type checker attempts to identify possible runtime errors (see <a href="#runtime-errors">Runtime Errors</a>), particularly <code>no_matching_overload</code> and <code>no_such_field</code>, ahead of runtime. It also serves to optimize execution speed by narrowing down the number of possible matching overloads for a function call, and by allowing for a more efficient (unboxed) runtime representation of values.</p> <p dir="auto">By construction, a CEL expression that does not use the dynamic features coming from <code>Struct</code>, <code>Value</code>, or <code>Any</code>, can be fully statically type-checked and all overloads can be resolved ahead of runtime.</p> <p dir="auto">If a CEL expression uses a mixture of dynamic and static features, a type checker will still attempt to derive as much information as possible and delegate undecidable type decisions to runtime.</p> <p dir="auto">The type checker is an optional phase of evaluation. Running the type checker does not affect the result of evaluation, it can only reject expressions as ill-typed in a given typing context.</p> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Evaluation</h2><a id="user-content-evaluation" class="anchor" aria-label="Permalink: Evaluation" href="#evaluation"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">For a given evaluation environment, a CEL expression will deterministically evaluate to either a value or an error. Here are how different expressions are evaluated:</p> <ul dir="auto"> <li><strong>Literals:</strong> the various kinds of literals (numbers, booleans, strings, bytes, and <code>null</code>) evaluate to the values they represent.</li> <li><strong>Variables:</strong> variables are looked up in the binding environment. An unbound variable evaluates to an error.</li> <li><strong>List, Map, and Message expressions:</strong> each sub-expression is evaluated and if any sub-expression results in an error, this expression results in an error. Otherwise, it results in the list, map, or message of the sub-expression results, or an error if one of the values is of the wrong type.</li> <li><strong>Field selection:</strong> see <a href="#field-selection">Field Selection</a>.</li> <li><strong>Macros:</strong> see <a href="#macros">Macros</a>.</li> <li><strong>Logical operators:</strong> see <a href="#logical-operators">Logical Operators</a>.</li> <li><strong>Other operators:</strong> operators are translated into specially-named functions and the sub-expressions become their arguments, for instance <code>e1 + e2</code> becomes <code>_+_(e1, e2)</code>, which is then evaluated as a normal function.</li> <li><strong>Normal functions:</strong> all argument sub-expressions are evaluated and if any results in an error, then this expression results in an error. Otherwise, the function is identified by its name and dispatched to a particular overload based on the types of the sub-expression values. See <a href="#functions">Functions</a>.</li> </ul> <p dir="auto">Because CEL is free of side effects, the order of evaluation among sub-expressions is not guaranteed. If multiple sub-expressions would evaluate to errors causing the enclosing expression to evaluate to an error, it will propagate one or more of the sub-expression errors, but it is not specified which ones.</p> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Evaluation Environment</h3><a id="user-content-evaluation-environment" class="anchor" aria-label="Permalink: Evaluation Environment" href="#evaluation-environment"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">A CEL expression is parsed and evaluated in the scope of a particular protocol buffer package, which controls name resolution as described above, and a binding context, which binds identifiers to values, errors, and functions. A given identifier has different meanings as a function name or as a variable, depending on the use. For instance in the expression <code>size(requests) &gt; size</code>, the first <code>size</code> is a function, and the second is a variable.</p> <p dir="auto">The CEL implementation provides mechanisms for adding bindings of variable names to either values or errors. The implementation will also provide function bindings for at least all the standard functions listed below.</p> <p dir="auto">Where feasible, CEL implementations ensure that a value bound to a variable name or returned by a custom function conforms to the CEL type declared for that value or, for dynamic typed values, <em>a</em> CEL type. Where implementations allow nonconforming values, (e.g. strings with invalid Unicode code points) to be provided to a CEL program, conformance must be enforced by the application embedding the CEL program in order to ensure type safety is maintained.</p> <p dir="auto">Some implementations might make use of a <em>context proto</em>, where a single protocol buffer message represents all variable bindings: each field in the message is a binding of the field name to the field value. This provides a convenient encapsulation of the binding environment.</p> <p dir="auto">The evaluation environment can also specify the expected type of the result. If the expected type is one of the protocol buffer wrapper messages, then CEL will attempt to convert the result to the wrapper message, or will raise an error if the conversion fails.</p> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Runtime Errors</h3><a id="user-content-runtime-errors" class="anchor" aria-label="Permalink: Runtime Errors" href="#runtime-errors"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">In general, when a runtime error is produced, expression evaluation is terminated; exceptions to this rule are discussed in <a href="#logical-operators">Logical Operators</a> and <a href="#macros">Macros</a>.</p> <p dir="auto">CEL provides the following built-in runtime errors:</p> <ul dir="auto"> <li><code>no_matching_overload</code>: this function has no overload for the types of the arguments.</li> <li><code>no_such_field</code>: a map or message does not contain the desired field.</li> </ul> <p dir="auto">There is no in-language representation of errors, no generic way to raise them, and no way to catch or bypass errors, except for the short-circuiting behavior of the logical operators, and macros.</p> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Logical Operators</h3><a id="user-content-logical-operators" class="anchor" aria-label="Permalink: Logical Operators" href="#logical-operators"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">In the conditional operator <code>e ? e1 : e2</code>, evaluates to <code>e1</code> if <code>e</code> evaluates to <code>true</code>, and <code>e2</code> if <code>e</code> evaluates to <code>false</code>. The untaken branch is presumed to not be executed, though that is an implementation detail.</p> <p dir="auto">In the boolean operators <code>&amp;&amp;</code> and <code>||</code>: if any of their operands uniquely determines the result (<code>false</code> for <code>&amp;&amp;</code> and <code>true</code> for <code>||</code>) the other operand may or may not be evaluated, and if that evaluation produces a runtime error, it will be ignored. This makes those operators commutative (in contrast to traditional boolean short-circuit operators). The rationale for this behavior is to allow the boolean operators to be mapped to indexed queries, and align better with SQL semantics.</p> <p dir="auto">To get traditional left-to-right short-circuiting evaluation of logical operators, as in C or other languages (also called "McCarthy Evaluation"), the expression <code>e1 &amp;&amp; e2</code> can be rewritten <code>e1 ? e2 : false</code>. Similarly, <code>e1 || e2</code> can be rewritten <code>e1 ? true : e2</code>.</p> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Macros</h3><a id="user-content-macros" class="anchor" aria-label="Permalink: Macros" href="#macros"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">CEL supports a small set of predefined macros. Macro invocations have the same syntax as function calls, but follow different type checking rules and runtime semantics than regular functions. An application of CEL opts-in to which macros to support, selecting from the predefined set of macros. The currently available macros are:</p> <ul dir="auto"> <li><code>has(e.f)</code>: tests whether a field is available. See "Field Selection" below.</li> <li><code>e.all(x, p)</code>: tests whether a predicate holds for all elements of a list <code>e</code> or keys of a map <code>e</code>. Here <code>x</code> is a simple identifier to be used in <code>p</code> which binds to the element or key. The <code>all()</code> macro combines per-element predicate results with the "and" (<code>&amp;&amp;</code>) operator, so if any predicate evaluates to <code>false</code>, the macro evaluates to <code>false</code>, ignoring any errors from other predicates.</li> <li><code>e.exists(x, p)</code>: like the <code>all()</code> macro, but combines the predicate results with the "or" (<code>||</code>) operator, so if any predicate evaluates to <code>true</code>, the macro evaluates to <code>true</code>, ignoring any errors from other predicates.</li> <li><code>e.exists_one(x, p)</code>: like the <code>exists()</code> macro, but evaluates to <code>true</code> only if the predicate of exactly one element/key evaluates to <code>true</code>, and the rest to <code>false</code>. Any other combination of boolean results evaluates to <code>false</code>, and any predicate error causes the macro to raise an error.</li> <li><code>e.map(x, t)</code>: <ul dir="auto"> <li>transforms a list <code>e</code> by taking each element <code>x</code> to the function given by the expression <code>t</code>, which can use the variable <code>x</code>. For instance, <code>[1, 2, 3].map(n, n * n)</code> evaluates to <code>[1, 4, 9]</code>. Any evaluation error for any element causes the macro to raise an error.</li> <li>transforms a map <code>e</code> by taking each key in the map <code>x</code> to the function given by the expression <code>t</code>, which can use the variable <code>x</code>. For instance, <code>{'one': 1, 'two': 2}.map(k, k)</code> evaluates to <code>['one', 'two']</code>. Any evaluation error for any element causes the macro to raise an error.</li> </ul> </li> <li><code>e.map(x, p, t)</code>: Same as the two-arg map but with a conditional <code>p</code> filter before the value is transformed.</li> <li><code>e.filter(x, p)</code>: <ul dir="auto"> <li>for a list <code>e</code>, returns the sublist of all elements <code>x</code> which evaluate to <code>true</code> in the predicate expression <code>p</code> (which can use variable <code>x</code>). For instance, <code>[1, 2, 3].filter(i, i % 2 &gt; 0)</code> evaluates to <code>[1, 3]</code>. If no elements evaluate to <code>true</code>, the result is an empty list. Any evaluation error for any element causes the macro to raise an error.</li> <li>for a map <code>e</code>, returns the list of all map keys <code>x</code> which evaluate to <code>true</code> in the predicate expression <code>p</code> (which can use variable <code>x</code>). For instance, <code>{'one': 1, 'two': 2}.filter(k, k == 'one')</code> evaluates to <code>['one']</code>. If no elements evaluate to <code>true</code>, the result is an empty list. Any evaluation error for any element causes the macro to raise an error.</li> </ul> </li> </ul> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Field Selection</h3><a id="user-content-field-selection" class="anchor" aria-label="Permalink: Field Selection" href="#field-selection"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">A field selection expression, <code>e.f</code>, can be applied both to messages and to maps. For maps, selection is interpreted as the field being a string key.</p> <p dir="auto">The semantics depends on the type of the result of evaluating expression <code>e</code>:</p> <ol dir="auto"> <li>If <code>e</code> evaluates to a message and <code>f</code> is not declared in this message, the runtime error <code>no_such_field</code> is raised.</li> <li>If <code>e</code> evaluates to a message and <code>f</code> is declared, but the field is not set, the default value of the field's type will be produced. Note that this is <code>null</code> for messages or the according primitive default value as determined by proto2 or proto3 semantics.</li> <li>If <code>e</code> evaluates to a map, then <code>e.f</code> is equivalent to <code>e['f']</code> (where <code>f</code> is still being used as a meta-variable, e.g. the expression <code>x.foo</code> is equivalent to the expression <code>x['foo']</code> when <code>x</code> evaluates to a map).</li> <li>In all other cases, <code>e.f</code> evaluates to an error.</li> </ol> <p dir="auto">To test for the presence of a field, the boolean-valued macro <code>has(e.f)</code> can be used.</p> <ol dir="auto"> <li>If <code>e</code> evaluates to a map, then <code>has(e.f)</code> indicates whether the string <code>f</code> is a key in the map (note that <code>f</code> must syntactically be an identifier).</li> <li>If <code>e</code> evaluates to a message and <code>f</code> is not a declared field for the message, <code>has(e.f)</code> raises a <code>no_such_field</code> error.</li> <li>If <code>e</code> evaluates to a protocol buffers version 2 message and <code>f</code> is a defined field: <ul dir="auto"> <li>If <code>f</code> is a repeated field or map field, <code>has(e.f)</code> indicates whether the field is non-empty.</li> <li>If <code>f</code> is a singular or oneof field, <code>has(e.f)</code> indicates whether the field is set.</li> </ul> </li> <li>If <code>e</code> evaluates to a protocol buffers version 3 message and <code>f</code> is a defined field: <ul dir="auto"> <li>If <code>f</code> is a repeated field or map field, <code>has(e.f)</code> indicates whether the field is non-empty.</li> <li>If <code>f</code> is a oneof or singular message field, <code>has(e.f)</code> indicates whether the field is set.</li> <li>If <code>f</code> is some other singular field, <code>has(e.f)</code> indicates whether the field's value is its default value (zero for numeric fields, <code>false</code> for booleans, empty for strings and bytes).</li> </ul> </li> <li>In all other cases, <code>has(e.f)</code> evaluates to an error.</li> </ol> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Performance</h2><a id="user-content-performance" class="anchor" aria-label="Permalink: Performance" href="#performance"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Since one of the main applications for CEL is for execution of untrusted expressions with reliable containment, the time and space cost of evaluation is an essential part of the specification of the language. But we also want to give considerable freedom in how to implement the language. To balance these concerns, we specify only the time and space computational complexity of language constructs and standard functions (see <a href="#functions">Functions</a>).</p> <p dir="auto">CEL applications are responsible for noting the computational complexity of any extension functions they provide.</p> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Abstract Sizes</h3><a id="user-content-abstract-sizes" class="anchor" aria-label="Permalink: Abstract Sizes" href="#abstract-sizes"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Space and time complexity will be measured in terms of an abstract size measurement of CEL expressions and values. The size of a CEL value depends on its type:</p> <ul dir="auto"> <li><em>string</em>: The size is its length, i.e. the number of code points, plus a constant.</li> <li><em>bytes</em>: The size is its length, i.e. the number of bytes, plus a constant.</li> <li><em>list</em>: The size is the sum of sizes of its entries, plus a constant.</li> <li><em>map</em>: The size is the sum of the key size plus the value size for all of its entries, plus a constant.</li> <li><em>message</em>: The size is the sum of the size of all fields, plus a constant.</li> <li>All other values have constant size.</li> </ul> <p dir="auto">The size of a CEL program is:</p> <ul dir="auto"> <li><em>string literal</em>: The size of the resulting value.</li> <li><em>bytes literal</em>: The size of the resulting value.</li> <li>Grammatical aggregates are the sum of the size of their components.</li> <li>Grammatical primitives other than above have constant size.</li> </ul> <p dir="auto">Thus, the size of a CEL program is bounded by either the length of the source text string or the bytes of the proto-encoded AST.</p> <p dir="auto">The inputs to a CEL expression are the <em>bindings</em> given to the evaluator and the <em>literals</em> within the expression itself.</p> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Time Complexity</h3><a id="user-content-time-complexity" class="anchor" aria-label="Permalink: Time Complexity" href="#time-complexity"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Unless otherwise noted, the time complexity of an expression is the sum of the time complexity of its sub-expressions, plus the sum of the sizes of the sub-expression values, plus a constant.</p> <p dir="auto">For instance, an expression <code>x</code> has constant time complexity since it has no sub-expressions. An expression <code>x != y</code> takes time proportional to the sum of sizes of the bindings of <code>x</code> and <code>y</code>, plus a constant.</p> <p dir="auto">Some functions cost less than this:</p> <ul dir="auto"> <li>The conditional expression <code>_?_:_</code>, only evaluates one of the alternative sub-expressions.</li> <li>For the <code>size()</code> function on lists and maps, the time is proportional to the length of its input, not its total size (plus the time of the sub-expression).</li> <li>The index operator on lists takes constant time (plus the time of the sub-expressions).</li> <li>The select operator on messages takes constant time (plus the time of the sub-expression).</li> </ul> <p dir="auto">Some functions take more time than this. The following functions take time proportional to the <em>product</em> of their input sizes (plus the time of the sub-expressions):</p> <ul dir="auto"> <li>The index operator on maps.</li> <li>The select operator on maps.</li> <li>The in operator.</li> <li>The <code>contains</code>, <code>startsWith</code>, <code>endsWith</code>, and <code>matches</code> functions on strings.</li> </ul> <p dir="auto">See below for the time cost of macros.</p> <p dir="auto">Implementations are free to provide a more performant implementation. For instance, a hashing implementation of maps would make indexing/selection faster, but we do not require such sophistication from all implementations.</p> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Space Complexity</h3><a id="user-content-space-complexity" class="anchor" aria-label="Permalink: Space Complexity" href="#space-complexity"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Unless otherwise noted, the space complexity of an expression is the sum of the space complexity of its sub-expressions, plus a constant. The exceptions are:</p> <ul dir="auto"> <li><em>Literals</em>: Message, map, and list literals allocate new space for their output.</li> <li><em>Concatenation</em>: The <code>_+_</code> operator on lists and strings allocate new space for their output.</li> </ul> <p dir="auto">See below for the space cost of macros.</p> <p dir="auto">We'll assume that bytes-to-string and string-to-bytes conversions do not need to allocate new space.</p> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Macro Performance</h3><a id="user-content-macro-performance" class="anchor" aria-label="Permalink: Macro Performance" href="#macro-performance"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Macros can take considerably more time and space than other constructs, and can lead to exponential behavior when nested or chained. For instance,</p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="[0,1].all(x, [0,1].all(x, ... [0,1].all(x, 1/0)...))"><pre class="notranslate"><code>[0,1].all(x, [0,1].all(x, ... [0,1].all(x, 1/0)...)) </code></pre></div> <p dir="auto">takes exponential (in the size of the expression) time to evaluate, while</p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="[&quot;foo&quot;,&quot;bar&quot;].map(x, [x+x,x+x]).map(x, [x+x,x+x])...map(x, [x+x,x+x])"><pre class="notranslate"><code>["foo","bar"].map(x, [x+x,x+x]).map(x, [x+x,x+x])...map(x, [x+x,x+x]) </code></pre></div> <p dir="auto">is exponential in both time and space.</p> <p dir="auto">The time and space cost of macros is the cost of the range sub-expression <code>e</code>, plus the following:</p> <ul dir="auto"> <li><code>has(e.f)</code>: Space is constant. <ul dir="auto"> <li>If <code>e</code> is a map, time is linear in size of <code>e</code>.</li> <li>If <code>e</code> is a message, time is constant.</li> </ul> </li> <li><code>e.all(x, p)</code>, <code>e.exists(x, p)</code>, and <code>e.exists_one(x, p)</code> <ul dir="auto"> <li>Time is the sum of the time of <code>p</code> for each element of <code>e</code>.</li> <li>Space is constant.</li> </ul> </li> <li><code>e.map(x, t)</code> <ul dir="auto"> <li>Time is the sum of time of <code>t</code> for each element of <code>e</code>.</li> <li>Space is the sum of space of <code>t</code> for each element of <code>e</code>, plus a constant.</li> </ul> </li> <li><code>e.filter(x, t)</code> <ul dir="auto"> <li>Time is the sum of time of <code>t</code> for each element of <code>e</code>.</li> <li>Space is the space of <code>e</code>.</li> </ul> </li> </ul> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Performance Limits</h3><a id="user-content-performance-limits" class="anchor" aria-label="Permalink: Performance Limits" href="#performance-limits"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Putting this all together, we can make the following statements about the cost of evaluation. Let <code>P</code> be the non-literal size of the expression, <code>L</code> be the size of the literals, <code>B</code> be the size of the bindings, and <code>I=B+L</code> be the total size of the inputs.</p> <ul dir="auto"> <li>The macros other than <code>has()</code> are the only avenue for exponential behavior. This can be curtailed by the implementation allowing applications to set limits on the recursion or chaining of macros, or disable them entirely.</li> <li>The concatenation operator <code>_+_</code> is the only operator that dramatically increases the space complexity, with the program <code>x + x + ... + x</code> taking time and space <code>O(B * P^2)</code>.</li> <li>The string-detection functions (<code>contains()</code> and friends) yield a boolean result, thus cannot be nested to drive exponential or even higher polynomial cost. We can bound the time cost by <code>O(B^2 * P)</code>, with a limiting case being <code>x.contains(y) || x.contains(y) || ...</code>.</li> <li>The map indexing operators yield a smaller result than their input, and thus are also limited in their ability to increase the cost. A particularly bad case would be an expensive selection that returns a subcomponent that contains the majority of the size of the aggregate, resulting in a time cost of <code>O(P * I)</code>, and see below.</li> <li>Eliminating all of the above and using only default-cost functions, plus aggregate literals, time and space are limited <code>O(P * I)</code>. A limiting time example is <code>size(x) + size(x) + ...</code>. A limiting time and space example is <code>[x, x, ..., x]</code>.</li> </ul> <p dir="auto">Note that custom function will alter this analysis if they are more expensive than the default costs.</p> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Functions</h2><a id="user-content-functions" class="anchor" aria-label="Permalink: Functions" href="#functions"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">CEL functions have no observable side effects (there may be side effects like logging or such which are not observable from CEL). The default argument evaluation strategy for functions is strict, with exceptions from this rule discussed in <a href="#logical-operators">Logical Operators</a> and <a href="#macros">Macros</a>.</p> <p dir="auto">Functions are specified by a set of overloads. Each overload defines the number and type of arguments and the type of the result, as well as an opaque computation. Argument and result types can use type variables to express overloads which work on lists and maps. At runtime, a matching overload is selected and the according computation invoked. If no overload matches, the runtime error <code>no_matching_overload</code> is raised (see also <a href="#errors">Runtime Errors</a>). For example, the standard function <code>size</code> is specified by the following overloads:</p> <markdown-accessiblity-table><table border="1"> <tbody><tr> <th rowspan="4"> size </th> <td> (string) -&gt; int </td> <td> string length </td> </tr> <tr> <td> (bytes) -&gt; int </td> <td> bytes length </td> </tr> <tr> <td> (list(A)) -&gt; int </td> <td> list size </td> </tr> <tr> <td> (map(A, B)) -&gt; int </td> <td> map size </td> </tr> </tbody></table></markdown-accessiblity-table> <p dir="auto">Overloads must have non-overlapping argument types, after erasure of all type variables (similar as type erasure in Java). Thus an implementation can implement overload resolution by simply mapping all argument types to a strong hash.</p> <p dir="auto">Operator sub-expressions are treated as calls to specially-named built-in functions. For instance, the expression <code>e1 + e2</code> is dispatched to the function <code>_+_</code> with arguments <code>e1</code> and <code>e2</code>. Note that since <code>_+_</code> is not an identifier, there would be no way to write this as a normal function call.</p> <p dir="auto">See <a href="#standard-definitions">Standard Definitions</a> for the list of all predefined functions and operators.</p> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Extension Functions</h3><a id="user-content-extension-functions" class="anchor" aria-label="Permalink: Extension Functions" href="#extension-functions"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">It is possible to add extension functions to CEL, which then behave consistently with standard functions. The mechanism for doing this is implementation dependent and usually highly curated. For example, an application domain of CEL can add a new overload to the <code>size</code> function above, provided this overload's argument types do not overlap with any existing overload. For methodological reasons, CEL does not allow overloading operators.</p> <p dir="auto">Like standard functions, extension functions must be free from observable side effects in order to prevent expressions from having undefined results, since CEL does not guarantee evaluation order of sub-expressions.</p> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Receiver Call Style</h3><a id="user-content-receiver-call-style" class="anchor" aria-label="Permalink: Receiver Call Style" href="#receiver-call-style"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">A function overload can be declared to use receiver call-style, so it must be called as <code>e1.f(e2)</code> instead of <code>f(e1, e2)</code>. Overloads with different call styles are non-overlapping per definition, regardless of their types.</p> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Standard Definitions</h2><a id="user-content-standard-definitions" class="anchor" aria-label="Permalink: Standard Definitions" href="#standard-definitions"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">All predefined operators, functions and constants are listed in the table below. For each symbol, the available overloads are listed. Operator symbols use a notation like <code>_+_</code> where <code>_</code> is a placeholder for an argument.</p> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Equality</h3><a id="user-content-equality" class="anchor" aria-label="Permalink: Equality" href="#equality"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Equality (<code>_==_</code>) and inequality (<code>_!=_</code>) are defined for all types. Inequality is the logical negation of equality, i.e. <code>e1 != e2</code> is the same as <code>!(e1 == e2)</code> for all expressions <code>e1</code> and <code>e2</code>.</p> <p dir="auto">Type-checking asserts that arguments to equality operators must be the same type. If the argument types differ, the type-checker will raise an error. However, if at least one argument is dynamically typed, the type-checker considers all arguments dynamic and defers type-agreement checks to the interpreter.</p> <p dir="auto">The type-checker uses homogeneous equality to surface potential logical errors during static analysis, but the runtime uses heterogeneous equality with a definition of <a href="#Numbers">numeric equality</a> which treats all numeric types as though they exist on a continuous number line. Semantically, equality would be expressed within in CEL as follows:</p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="type(x) in [double, int, uint] &amp;&amp; type(y) in [double, int, uint] ? numericEquals(x, y) : type(x) == type(y) ? x == y : false"><pre lang="cel" class="notranslate"><code>type(x) in [double, int, uint] &amp;&amp; type(y) in [double, int, uint] ? numericEquals(x, y) : type(x) == type(y) ? x == y : false </code></pre></div> <p dir="auto">CEL's support for boxed primitives relies on heterogeneous equality to ensure that comparisons to <code>null</code> evaluate to <code>true</code> or <code>false</code> rather than error. This behavior is also useful for evaluating JSON data where all numbers may be provided as <code>double</code> or, depending on the underlying JSON implementation, possibly <code>int</code>. This potential discrepancy between how runtimes handle dynamic data is further motivation for supporting separate behaviors at type-check and interpretation.</p> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Numbers</h4><a id="user-content-numbers" class="anchor" aria-label="Permalink: Numbers" href="#numbers"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">The numeric types of <code>int</code>, <code>uint</code>, and <code>double</code> are compared as though they exist on a continuous number line where two numbers <code>x</code> and <code>y</code> are equal if <code>!(x &lt; y || x &gt; y)</code>. Since it is possible to compare numeric types without type conversion, CEL uses this definition for <code>numericEquals</code> to support comparison across numeric types.</p> <p dir="auto">This property of cross-type numeric equality is essential for supporting JSON in a way which mostly closely matches user expectations. The following expressions are equivalent as the type-checker cannot infer the type of the <code>json.number</code> in the expression since it is considered <code>dyn</code> typed:</p> <p dir="auto">Index into a map:</p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="{1: 'hello', 2: 'world'}[json.number] {1: 'hello', 2: 'world'}[int(json.number)]"><pre class="notranslate"><code>{1: 'hello', 2: 'world'}[json.number] {1: 'hello', 2: 'world'}[int(json.number)] </code></pre></div> <p dir="auto">Set membership test of a json number in a list of integers:</p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="json.number in [1, 2, 3] int(json.number) in [1, 2, 3]"><pre class="notranslate"><code>json.number in [1, 2, 3] int(json.number) in [1, 2, 3] </code></pre></div> <p dir="auto">The <code>double</code> type follows the IEEE 754 standard. Not-a-number (<code>NaN</code>) values compare as unequal, e.g. <code>NaN == NaN // false</code> and <code>NaN != NaN // true</code>.</p> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Lists and Maps</h4><a id="user-content-lists-and-maps" class="anchor" aria-label="Permalink: Lists and Maps" href="#lists-and-maps"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Two <code>list</code> values equal if their entries at each ordinal are equal. For lists <code>a</code> and <code>b</code> with length <code>N</code>, <code>a == b</code> is equivalent to:</p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="a[0] == b[0] &amp;&amp; a[1] == b[1] &amp;&amp; ... &amp;&amp; a[N-1] == b[N-1]"><pre class="notranslate"><code>a[0] == b[0] &amp;&amp; a[1] == b[1] &amp;&amp; ... &amp;&amp; a[N-1] == b[N-1] </code></pre></div> <p dir="auto">Two <code>map</code> values are equal if their entries are the same. For maps <code>a</code> and <code>b</code> with keyset <code>k1, k2, ..., kN</code>, <code>a == b</code> equality is equivalent to:</p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="a[k1] == b[k1] &amp;&amp; a[k2] == b[k2] &amp;&amp; ... &amp;&amp; a[kN] == b[kN]"><pre class="notranslate"><code>a[k1] == b[k1] &amp;&amp; a[k2] == b[k2] &amp;&amp; ... &amp;&amp; a[kN] == b[kN] </code></pre></div> <p dir="auto">In short, when <code>list</code> lengths / <code>map</code> key sets are the same, and all element comparisons are <code>true</code>, the result is <code>true</code>.</p> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Protocol Buffers</h4><a id="user-content-protocol-buffers" class="anchor" aria-label="Permalink: Protocol Buffers" href="#protocol-buffers"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">CEL uses the C++ <a href="https://developers.google.com/protocol-buffers/docs/reference/cpp/google.protobuf.util.message_differencer#MessageDifferencer.Equals.details" rel="nofollow"><code>MessageDifferencer::Equals</code></a> semantics for comparing Protocol Buffer messages across all runtimes. For two messages to be equal:</p> <ul dir="auto"> <li>Both messages must share the same type name and <code>Descriptor</code> instance;</li> <li>Both messages must have the same set fields;</li> <li>All primitive typed fields compare equal by value, e.g. <code>string</code>, <code>int64</code>;</li> <li>All elements of <code>repeated</code> fields compare in-order as <code>true</code>;</li> <li>All entries of <code>map</code> fields compare order-independently as <code>true</code>;</li> <li>All fields of <code>message</code> and <code>group</code> typed fields compare true, with the comparison being performed as if by recursion.</li> <li>All unknown fields compare <code>true</code> using byte equality.</li> </ul> <p dir="auto">In addition to the publicly documented behaviors for C++ protobuf equality, there are some implementation behaviors which are important to mention:</p> <ul dir="auto"> <li>The <code>double</code> type follows the IEEE 754 standard where not-a-number (<code>NaN</code>) values compare as unequal, e.g. <code>NaN == NaN // false</code> and <code>NaN != NaN // true</code>.</li> <li>All <code>google.protobuf.Any</code> typed fields are unpacked before comparison, unless the <code>type_url</code> cannot be resolved, in which case the comparison falls back to byte equality.</li> </ul> <p dir="auto">Protocol buffer equality semantics in C++ are generally consistent with CEL's definition of heterogeneous equality. Note, Java and Go proto equality implementations do not follow IEEE 754 for <code>NaN</code> values and do not unpack <code>google.protobuf.Any</code> values before comparison. These comparison differences can result in false negatives or false positives; consequently, CEL provides a uniform definition across runtimes to ensure consistent evaluation across runtimes.</p> <p dir="auto">There is one edge case where CEL and protobuf equality will produce different results; however, this edge case is sufficiently unlikely that the difference is acceptable:</p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="// Protocol buffer definition message Msg { repeated google.protobuf.Any values; } // CEL - Produces `false` according to protobuf equality since the types of // Int32Value and FloatValue are not equal. Msg{values: [google.protobuf.Int32Value{value: 1}]} == Msg{values: [google.protobuf.FloatValue{value: 1.0}]} // CEL - Produces `true` according to CEL equality with well-known // protobuf type unwrapping of the list elements within `values` // where the list values are unwrapped to CEL numbers and compared // using `numericEquals`. Msg{values: [google.protobuf.Int32Value{value: 1}]}.values == Msg{values: [google.protobuf.FloatValue{value: 1.0}]}.values"><pre class="notranslate"><code>// Protocol buffer definition message Msg { repeated google.protobuf.Any values; } // CEL - Produces `false` according to protobuf equality since the types of // Int32Value and FloatValue are not equal. Msg{values: [google.protobuf.Int32Value{value: 1}]} == Msg{values: [google.protobuf.FloatValue{value: 1.0}]} // CEL - Produces `true` according to CEL equality with well-known // protobuf type unwrapping of the list elements within `values` // where the list values are unwrapped to CEL numbers and compared // using `numericEquals`. Msg{values: [google.protobuf.Int32Value{value: 1}]}.values == Msg{values: [google.protobuf.FloatValue{value: 1.0}]}.values </code></pre></div> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Ordering</h3><a id="user-content-ordering" class="anchor" aria-label="Permalink: Ordering" href="#ordering"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Ordering operators are defined for <code>int</code>, <code>uint</code>, <code>double</code>, <code>string</code>, <code>bytes</code>, <code>bool</code>, as well as <code>timestamp</code> and <code>duration</code>. Runtime ordering is also supported across <code>int</code>, <code>uint</code>, and <code>double</code> for consistency with the runtime equality definition for numeric types.</p> <p dir="auto">Strings and bytes obey lexicographic ordering of the byte values. Because strings are encoded in UTF-8, strings consequently also obey lexicographic ordering of their Unicode code points.</p> <p dir="auto">The ordering operators obey the usual algebraic properties, i.e. <code>e1 &lt;= e2</code> gives the same result as <code>!(e1 &gt; e2)</code> as well as <code>(e1 &lt; e2) || (e1 == e2)</code>.</p> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Overflow</h3><a id="user-content-overflow" class="anchor" aria-label="Permalink: Overflow" href="#overflow"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Arithmetic operations raise an error when the results exceed the range of the integer type (int, uint) or the timestamp or duration type. An error is also raised for conversions which exceed the range of the target type.</p> <p dir="auto">There are a few additional considerations to keep in mind with respect to how and when certain types will overflow:</p> <ul dir="auto"> <li>Duration values are limited to a single int64 value, or roughly +-290 years.</li> <li>Timestamp values are limited to the range of values which can be serialized as a string: ["0001-01-01T00:00:00Z", "9999-12-31T23:59:59.999999999Z"].</li> <li>Double to int conversions are limited to (minInt, maxInt) non-inclusive.</li> </ul> <p dir="auto">Note, that whether the minimum or maximum integer value will roundtrip successfully int -&gt; double -&gt; int can be compiler dependent which is the motivation for the conservative round-tripping behavior.</p> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Timezones</h3><a id="user-content-timezones" class="anchor" aria-label="Permalink: Timezones" href="#timezones"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Timezones are expressed in the following grammar:</p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="TimeZone = &quot;UTC&quot; | LongTZ | FixedTZ ; LongTZ = ? list available at https://www.joda.org/joda-time/timezones.html ? ; FixedTZ = ( &quot;+&quot; | &quot;-&quot; ) Digit Digit &quot;:&quot; Digit Digit ; Digit = &quot;0&quot; | &quot;1&quot; | ... | &quot;9&quot; ;"><pre lang="grammar" class="notranslate"><code>TimeZone = "UTC" | LongTZ | FixedTZ ; LongTZ = ? list available at https://www.joda.org/joda-time/timezones.html ? ; FixedTZ = ( "+" | "-" ) Digit Digit ":" Digit Digit ; Digit = "0" | "1" | ... | "9" ; </code></pre></div> <p dir="auto">Fixed timezones are explicit hour and minute offsets from UTC. Long timezone names are like <code>Europe/Paris</code>, <code>CET</code>, or <code>US/Central</code>.</p> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Regular Expressions</h3><a id="user-content-regular-expressions" class="anchor" aria-label="Permalink: Regular Expressions" href="#regular-expressions"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Regular expressions follow the <a href="https://github.com/google/re2/wiki/Syntax">RE2 syntax</a>. Regular expression matches succeed if they match a substring of the argument. Use explicit anchors (<code>^</code> and <code>$</code>) in the pattern to force full-string matching, if desired.</p> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Standard Environment</h3><a id="user-content-standard-environment" class="anchor" aria-label="Permalink: Standard Environment" href="#standard-environment"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Presence and Comprehension Macros</h4><a id="user-content-presence-and-comprehension-macros" class="anchor" aria-label="Permalink: Presence and Comprehension Macros" href="#presence-and-comprehension-macros"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto"><strong>has(message.field)</strong> - Checks if a field exists within a message. This macro supports proto2, proto3, and map key accesses. Only map accesses using the select notation are supported.</p> <p dir="auto"><strong>Signatures</strong></p> <ul dir="auto"> <li><code>has(message.field) -&gt; bool</code></li> </ul> <p dir="auto"><strong>Examples</strong></p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="// `true` if the 'address' field exists in the 'user' message has(user.address) // `true` if map 'm' has a key named 'key_name' defined. The value may be null // as null does not connote absence in CEL. has(m.key_name) // `false` if the 'items' field is not set in the 'order' message has(order.items) // `false` if the 'user_id' key is not present in the 'sessions' map has(sessions.user_id)"><pre class="notranslate"><code>// `true` if the 'address' field exists in the 'user' message has(user.address) // `true` if map 'm' has a key named 'key_name' defined. The value may be null // as null does not connote absence in CEL. has(m.key_name) // `false` if the 'items' field is not set in the 'order' message has(order.items) // `false` if the 'user_id' key is not present in the 'sessions' map has(sessions.user_id) </code></pre></div> <p dir="auto"><strong>all -</strong> Tests whether all elements in the input list or all keys in a map satisfy the given predicate. The all macro behaves in a manner consistent with the Logical AND operator including in how it absorbs errors and short-circuits.</p> <p dir="auto"><strong>Signatures</strong></p> <ul dir="auto"> <li><code>list(A).all(A, predicate(A) -&gt; bool) -&gt; bool</code></li> <li><code>map(A, B).all(A, predicate(A) -&gt; bool) -&gt; bool</code></li> </ul> <p dir="auto"><strong>Examples</strong></p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="[1, 2, 3].all(x, x &gt; 0) // true [1, 2, 0].all(x, x &gt; 0) // false ['apple', 'banana', 'cherry'].all(fruit, fruit.size() &gt; 3) // true [3.14, 2.71, 1.61].all(num, num &lt; 3.0) // false {'a': 1, 'b': 2, 'c': 3}.all(key, key != 'b') // false"><pre class="notranslate"><code>[1, 2, 3].all(x, x &gt; 0) // true [1, 2, 0].all(x, x &gt; 0) // false ['apple', 'banana', 'cherry'].all(fruit, fruit.size() &gt; 3) // true [3.14, 2.71, 1.61].all(num, num &lt; 3.0) // false {'a': 1, 'b': 2, 'c': 3}.all(key, key != 'b') // false </code></pre></div> <p dir="auto"><strong>exists</strong> - Tests whether any value in the list or any key in the map satisfies the predicate expression. The exists macro behaves in a manner consistent with the Logical OR operator including in how it absorbs errors and short-circuits.</p> <p dir="auto"><strong>Signatures</strong></p> <ul dir="auto"> <li><code>list(A).exists(A, predicate(A) -&gt; bool) -&gt; bool</code></li> <li><code>map(A,B).exists(A, predicate(A) -&gt; bool) -&gt; bool</code></li> </ul> <p dir="auto"><strong>Examples</strong></p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="[1, 2, 3].exists(i, i % 2 != 0) // true [].exists(i, i &gt; 0) // false [0, -1, 5].exists(num, num &lt; 0) // true {'x': 'foo', 'y': 'bar'}.exists(key, key.startsWith('z')) // false"><pre class="notranslate"><code>[1, 2, 3].exists(i, i % 2 != 0) // true [].exists(i, i &gt; 0) // false [0, -1, 5].exists(num, num &lt; 0) // true {'x': 'foo', 'y': 'bar'}.exists(key, key.startsWith('z')) // false </code></pre></div> <p dir="auto"><strong>exists_one</strong> - Tests whether exactly one list element or map key satisfies the predicate expression. This macro does not short-circuit in order to remain consistent with logical operators being the only operators which can absorb errors within CEL.</p> <p dir="auto"><strong>Signatures</strong></p> <ul dir="auto"> <li><code>list(A).exists_one(A, predicate(A)) -&gt; bool</code></li> <li><code>map(A,B).exists_one(A, predicate(A)) -&gt; bool</code></li> </ul> <p dir="auto"><strong>Examples</strong></p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="[1, 2, 2].exists_one(i, i &lt; 2) // true {'a': 'hello', 'aa': 'hellohello'}.exists_one(k, k.startsWith('a')) // false [1, 2, 3, 4].exists_one(num, num % 2 == 0) // false"><pre class="notranslate"><code>[1, 2, 2].exists_one(i, i &lt; 2) // true {'a': 'hello', 'aa': 'hellohello'}.exists_one(k, k.startsWith('a')) // false [1, 2, 3, 4].exists_one(num, num % 2 == 0) // false </code></pre></div> <p dir="auto"><strong>filter</strong> - Returns a list containing only the elements from the input list that satisfy the given predicate</p> <p dir="auto"><strong>Signatures</strong></p> <ul dir="auto"> <li><code>list(A).filter(A, function(A) -&gt; bool) -&gt; list(A)</code></li> <li><code>map(A, B).filter(A, function(A) -&gt; bool) -&gt; list(A)</code></li> </ul> <p dir="auto"><strong>Examples</strong></p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="[1, 2, 3].filter(x, x &gt; 1) // [2, 3] ['cat', 'dog', 'bird', 'fish'].filter(pet, pet.size() == 3) // ['cat', 'dog'] [{'a': 10, 'b': 5, 'c': 20}].map(m, m.filter(key, m[key] &gt; 10)) // [['c']]"><pre class="notranslate"><code>[1, 2, 3].filter(x, x &gt; 1) // [2, 3] ['cat', 'dog', 'bird', 'fish'].filter(pet, pet.size() == 3) // ['cat', 'dog'] [{'a': 10, 'b': 5, 'c': 20}].map(m, m.filter(key, m[key] &gt; 10)) // [['c']] </code></pre></div> <p dir="auto"><strong>map</strong> - Returns a list where each element is the result of applying the transform expression to the corresponding input list element or input map key.</p> <p dir="auto">There are two forms of the map macro:</p> <ul dir="auto"> <li>The three argument form transforms all elements.</li> <li>The four argument form transforms only elements which satisfy the predicate.</li> </ul> <p dir="auto">The four argument form of the macro exists to simplify combined filter / map operations.</p> <p dir="auto"><strong>Signatures</strong></p> <ul dir="auto"> <li><code>list(A).map(A, function(A) -&gt; T) -&gt; list(T)</code></li> <li><code>list(A).map(A, function(A) -&gt; bool, function(A) -&gt; T) -&gt; list(T)</code></li> <li><code>map(A, B).map(A, function(A) -&gt; T) -&gt; list(T)</code></li> <li><code>map(A, B).map(A, function(A) -&gt; bool, function(A) -&gt; T) -&gt; list(T)</code></li> </ul> <p dir="auto"><strong>Examples</strong></p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="[1, 2, 3].map(x, x * 2) // [2, 4, 6] [5, 10, 15].map(x, x / 5) // [1, 2, 3] ['apple', 'banana'].map(fruit, fruit.upperAscii()) // ['APPLE', 'BANANA'] [1, 2, 3, 4].map(num, num % 2 == 0, num * 2) // [4, 8]"><pre class="notranslate"><code>[1, 2, 3].map(x, x * 2) // [2, 4, 6] [5, 10, 15].map(x, x / 5) // [1, 2, 3] ['apple', 'banana'].map(fruit, fruit.upperAscii()) // ['APPLE', 'BANANA'] [1, 2, 3, 4].map(num, num % 2 == 0, num * 2) // [4, 8] </code></pre></div> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Logical Operators</h4><a id="user-content-logical-operators-1" class="anchor" aria-label="Permalink: Logical Operators" href="#logical-operators-1"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto"><strong>Logical NOT (!)</strong> - Takes a boolean value as input and returns the opposite boolean value.</p> <p dir="auto"><strong>Signatures:</strong></p> <ul dir="auto"> <li><code>!bool -&gt; bool</code></li> </ul> <p dir="auto"><strong>Examples:</strong></p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="!true // false !false // true !error // error"><pre class="notranslate"><code>!true // false !false // true !error // error </code></pre></div> <p dir="auto"><strong>Logical OR (||)</strong> - Compute the logical OR of two or more values. Errors and unknown values are considered valid inputs to this operator and will not halt evaluation.</p> <p dir="auto"><strong>Signatures:</strong></p> <ul dir="auto"> <li><code>bool || bool -&gt; bool</code></li> </ul> <p dir="auto"><strong>Examples:</strong></p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="true || false // true false || false // false error || true // true error || false // error"><pre class="notranslate"><code>true || false // true false || false // false error || true // true error || false // error </code></pre></div> <p dir="auto"><strong>Logical AND (&amp;&amp;)</strong> - Compute the logical AND of two or more values. Errors and unknown values are considered valid inputs to this operator and will not halt evaluation.</p> <p dir="auto"><strong>Signatures:</strong></p> <ul dir="auto"> <li><code>bool &amp;&amp; bool -&gt; bool</code></li> </ul> <p dir="auto"><strong>Examples:</strong></p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="true &amp;&amp; true // true true &amp;&amp; false // false error &amp;&amp; true // error error &amp;&amp; false // false"><pre class="notranslate"><code>true &amp;&amp; true // true true &amp;&amp; false // false error &amp;&amp; true // error error &amp;&amp; false // false </code></pre></div> <p dir="auto"><strong>Conditional Operator (? : )</strong> - The conditional or ternary operator which evaluates the test condition and only one of the remaining sub-expressions</p> <p dir="auto"><strong>Signatures:</strong></p> <ul dir="auto"> <li><code>bool ? A : A -&gt; A</code></li> </ul> <p dir="auto"><strong>Examples:</strong></p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="true ? 1 : 2 // 1 false ? &quot;a&quot; : &quot;b&quot; // &quot;b&quot; true ? error : value // error false ? error : value // value (2 &lt; 5) ? 'yes' : 'no' // 'yes' ('hello'.size() &gt; 10) ? 1 / 0 : 42 // 42"><pre class="notranslate"><code>true ? 1 : 2 // 1 false ? "a" : "b" // "b" true ? error : value // error false ? error : value // value (2 &lt; 5) ? 'yes' : 'no' // 'yes' ('hello'.size() &gt; 10) ? 1 / 0 : 42 // 42 </code></pre></div> <p dir="auto"><strong>Note:</strong></p> <ul dir="auto"> <li><code>error</code> is a special value in CEL that represents an error condition. Operations involving <code>error</code> typically propagate the error.</li> <li>This documentation provides examples for a few CEL operators. The complete CEL specification includes many more operators and functions.</li> </ul> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Arithmetic Operators</h4><a id="user-content-arithmetic-operators" class="anchor" aria-label="Permalink: Arithmetic Operators" href="#arithmetic-operators"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto"><strong>Negation (-)</strong> - Takes a numeric value (int or double) as input and returns its negated value.</p> <p dir="auto"><strong>Signatures:</strong></p> <ul dir="auto"> <li><code>-int -&gt; int</code></li> <li><code>-double -&gt; double</code></li> </ul> <p dir="auto"><strong>Examples:</strong></p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="-5 // -5 -3.14 // -3.14"><pre class="notranslate"><code>-5 // -5 -3.14 // -3.14 </code></pre></div> <p dir="auto"><strong>Addition (+)</strong> - Adds two numeric values or concatenates two strings, bytes, or lists.</p> <p dir="auto"><strong>Signatures:</strong></p> <ul dir="auto"> <li>Numeric addition <ul dir="auto"> <li><code>int + int -&gt; int</code></li> <li><code>uint + uint -&gt; uint</code></li> <li><code>double + double -&gt; double</code></li> </ul> </li> <li>Time and duration addition <ul dir="auto"> <li><code>google.protobuf.Timestamp + google.protobuf.Duration -&gt; google.protobuf.Timestamp</code></li> <li><code>google.protobuf.Duration + google.protobuf.Timestamp -&gt; google.protobuf.Timestamp</code></li> <li><code>google.protobuf.Duration + google.protobuf.Duration -&gt; google.protobuf.Duration</code></li> </ul> </li> <li>Concatenation <ul dir="auto"> <li><code>string + string -&gt; string</code></li> <li><code>bytes + bytes -&gt; bytes</code></li> <li><code>list(A) + list(A) -&gt; list(A)</code></li> </ul> </li> </ul> <p dir="auto"><strong>Examples:</strong></p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="1 + 2 // 3 3.14 + 1.59 // 4.73 &quot;Hello, &quot; + &quot;world!&quot; // &quot;Hello, world!&quot; [1] + [2, 3] // [1, 2, 3] duration('1m') + duration('1s') // duration('1m1s') timestamp('2023-01-01T00:00:00Z') + duration('24h') // timestamp('2023-01-02T00:00:00Z')"><pre class="notranslate"><code>1 + 2 // 3 3.14 + 1.59 // 4.73 "Hello, " + "world!" // "Hello, world!" [1] + [2, 3] // [1, 2, 3] duration('1m') + duration('1s') // duration('1m1s') timestamp('2023-01-01T00:00:00Z') + duration('24h') // timestamp('2023-01-02T00:00:00Z') </code></pre></div> <p dir="auto"><strong>Subtraction (-)</strong> - Subtracts two numeric values or calculates the duration between two timestamps.</p> <p dir="auto"><strong>Signatures:</strong></p> <ul dir="auto"> <li>Numeric subtraction <ul dir="auto"> <li><code>int - int -&gt; int</code></li> <li><code>uint - uint -&gt; uint</code></li> <li><code>double - double -&gt; double</code></li> </ul> </li> <li>Time and duration subtraction <ul dir="auto"> <li><code>google.protobuf.Timestamp - google.protobuf.Timestamp -&gt; google.protobuf.Duration</code></li> <li><code>google.protobuf.Timestamp - google.protobuf.Duration -&gt; google.protobuf.Timestamp</code></li> <li><code>google.protobuf.Duration - google.protobuf.Duration -&gt; google.protobuf.Duration</code></li> </ul> </li> </ul> <p dir="auto"><strong>Examples:</strong></p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="5 - 3 // 2 10.5 - 2.0 // 8.5 duration('1m') - duration('1s') // duration('59s') timestamp('2023-01-10T12:00:00Z') - timestamp('2023-01-10T00:00:00Z') // duration('12h')"><pre class="notranslate"><code>5 - 3 // 2 10.5 - 2.0 // 8.5 duration('1m') - duration('1s') // duration('59s') timestamp('2023-01-10T12:00:00Z') - timestamp('2023-01-10T00:00:00Z') // duration('12h') </code></pre></div> <p dir="auto"><strong>Division (/)</strong> - Divides two numeric values.</p> <p dir="auto"><strong>Signatures:</strong></p> <ul dir="auto"> <li><code>int / int -&gt; int</code></li> <li><code>uint / uint -&gt; uint</code></li> <li><code>double / double -&gt; double</code></li> </ul> <p dir="auto"><strong>Examples:</strong></p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="10 / 2 // 5 7.0 / 2.0 // 3.5"><pre class="notranslate"><code>10 / 2 // 5 7.0 / 2.0 // 3.5 </code></pre></div> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Comparison Operators</h4><a id="user-content-comparison-operators" class="anchor" aria-label="Permalink: Comparison Operators" href="#comparison-operators"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Comparisons require strict type equality at type-check time. If types do not agree, then type-conversion is required in order to be explicit about the intention and inherent risks of comparing across types.</p> <p dir="auto">The one exception to this rule is numeric comparisons at runtime. Since CEL supports JSON in addition to Protocol Buffers, it must handle cases where the user intent was to compare an integer value to a JSON value within the int53 range. For this reason, numeric comparisons across type are supported at runtime as all numeric representations may be considered to exist along a shared number line independent of their representation in memory.</p> <p dir="auto"><strong>Equality (==)</strong> - Compares two values of the same type and returns <code>true</code> if they are equal, and <code>false</code> otherwise</p> <p dir="auto"><strong>Signatures:</strong></p> <ul dir="auto"> <li><code>A == A -&gt; bool</code> (where A can be any comparable type)</li> </ul> <p dir="auto"><strong>Examples:</strong></p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="1 == 1 // true &quot;hello&quot; == &quot;world&quot; // false bytes('hello') == b'hello' // true duration('1h') == duration('60m') // true dyn(3.0) == 3 // true"><pre class="notranslate"><code>1 == 1 // true "hello" == "world" // false bytes('hello') == b'hello' // true duration('1h') == duration('60m') // true dyn(3.0) == 3 // true </code></pre></div> <p dir="auto"><strong>Inequality (!=)</strong> - Takes two values of the same type and returns <code>true</code> if they are not equal, and <code>false</code> otherwise.</p> <p dir="auto"><strong>Signatures:</strong></p> <ul dir="auto"> <li><code>A != A -&gt; bool</code> (where A can be any comparable type)</li> </ul> <p dir="auto"><strong>Examples:</strong></p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="1 != 2     // true &quot;a&quot; != &quot;a&quot; // false 3.0 != 3.1 // true"><pre class="notranslate"><code>1 != 2     // true "a" != "a" // false 3.0 != 3.1 // true </code></pre></div> <p dir="auto"><strong>Less Than or Equal To (&lt;=)</strong> - Compares two values and returns <code>true</code> if the first value is less than or equal to the second value, and <code>false</code> otherwise</p> <p dir="auto"><strong>Signatures:</strong></p> <ul dir="auto"> <li><code>bool &lt;= bool -&gt; bool</code></li> <li><code>int &lt;= int -&gt; bool</code></li> <li><code>uint &lt;= uint -&gt; bool</code></li> <li><code>double &lt;= double -&gt; bool</code></li> <li><code>string &lt;= string -&gt; bool</code></li> <li><code>bytes &lt;= bytes -&gt; bool</code></li> <li><code>google.protobuf.Timestamp &lt;= google.protobuf.Timestamp -&gt; bool</code></li> <li><code>google.protobuf.Duration &lt;= google.protobuf.Duration -&gt; bool</code></li> </ul> <p dir="auto"><strong>Examples:</strong></p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="2 &lt;= 3 // true 'a' &lt;= 'b' // true timestamp('2023-08-25T12:00:00Z') &lt;= timestamp('2023-08-26T12:00:00Z') // true"><pre class="notranslate"><code>2 &lt;= 3 // true 'a' &lt;= 'b' // true timestamp('2023-08-25T12:00:00Z') &lt;= timestamp('2023-08-26T12:00:00Z') // true </code></pre></div> <p dir="auto"><strong>Less Than (&lt;)</strong> - Compares two values and returns <code>true</code> if the first value is less than the second value, and <code>false</code> otherwise</p> <p dir="auto"><strong>Signatures:</strong></p> <ul dir="auto"> <li><code>bool &lt; bool -&gt; bool</code></li> <li><code>int &lt; int -&gt; bool</code></li> <li><code>uint &lt; uint -&gt; bool</code></li> <li><code>double &lt; double -&gt; bool</code></li> <li><code>string &lt; string -&gt; bool</code></li> <li><code>bytes &lt; bytes -&gt; bool</code></li> <li><code>google.protobuf.Timestamp &lt; google.protobuf.Timestamp -&gt; bool</code></li> <li><code>google.protobuf.Duration &lt; google.protobuf.Duration -&gt; bool</code></li> </ul> <p dir="auto"><strong>Examples:</strong></p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="2 &lt; 3 // true 'a' &lt; 'b' // true duration('2h') &lt; duration('3h') // true -1 &lt; dyn(1u) // true"><pre class="notranslate"><code>2 &lt; 3 // true 'a' &lt; 'b' // true duration('2h') &lt; duration('3h') // true -1 &lt; dyn(1u) // true </code></pre></div> <p dir="auto"><strong>Greater Than or Equal To (&gt;=)</strong> - Compares two values and returns <code>true</code> if the first value is greater than or equal to the second value, and <code>false</code> otherwise</p> <p dir="auto"><strong>Signatures:</strong></p> <ul dir="auto"> <li><code>bool &gt;= bool -&gt; bool</code></li> <li><code>int &gt;= int -&gt; bool</code></li> <li><code>uint &gt;= uint -&gt; bool</code></li> <li><code>double &gt;= double -&gt; bool</code></li> <li><code>string &gt;= string -&gt; bool</code></li> <li><code>bytes &gt;= bytes -&gt; bool</code></li> <li><code>google.protobuf.Timestamp &gt;= google.protobuf.Timestamp -&gt; bool</code></li> <li><code>google.protobuf.Duration &gt;= google.protobuf.Duration -&gt; bool</code></li> </ul> <p dir="auto"><strong>Examples:</strong></p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="3 &gt;= 2 // true 'b' &gt;= 'a' // true duration('2h') + duration('1h1m') &gt;= duration('3h') // true 1 &gt;= dyn(18446744073709551615u) // false"><pre class="notranslate"><code>3 &gt;= 2 // true 'b' &gt;= 'a' // true duration('2h') + duration('1h1m') &gt;= duration('3h') // true 1 &gt;= dyn(18446744073709551615u) // false </code></pre></div> <p dir="auto"><strong>Greater Than (&gt;)</strong> - Compares two values and returns <code>true</code> if the first value is greater than the second value, and <code>false</code> otherwise</p> <p dir="auto"><strong>Signatures:</strong></p> <ul dir="auto"> <li><code>bool &gt; bool -&gt; bool</code></li> <li><code>int &gt; int -&gt; bool</code></li> <li><code>uint &gt; uint -&gt; bool</code></li> <li><code>double &gt; double -&gt; bool</code></li> <li><code>string &gt; string -&gt; bool</code></li> <li><code>bytes &gt; bytes -&gt; bool</code></li> <li><code>google.protobuf.Timestamp &gt; google.protobuf.Timestamp -&gt; bool</code></li> <li><code>google.protobuf.Duration &gt; google.protobuf.Duration -&gt; bool</code></li> </ul> <p dir="auto"><strong>Examples:</strong></p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="3 &gt; 2 // true 'b' &gt; 'a' // true 5u &gt; 3u // true"><pre class="notranslate"><code>3 &gt; 2 // true 'b' &gt; 'a' // true 5u &gt; 3u // true </code></pre></div> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">List Operators</h4><a id="user-content-list-operators" class="anchor" aria-label="Permalink: List Operators" href="#list-operators"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto"><strong>List Indexing ([])</strong> - list indexing. Constant time cost</p> <p dir="auto"><strong>Signatures:</strong></p> <ul dir="auto"> <li><code>list(A)[int] -&gt; A</code></li> </ul> <p dir="auto"><strong>Examples:</strong></p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="[1, 2, 3][1] // 2"><pre class="notranslate"><code>[1, 2, 3][1] // 2 </code></pre></div> <p dir="auto"><strong>List Membership (in)</strong> - Checks if a value is present in a list. Time cost is proportional to the product of the size of both arguments.</p> <p dir="auto"><strong>Signatures:</strong></p> <ul dir="auto"> <li><code>A in list(A) -&gt; bool</code></li> </ul> <p dir="auto"><strong>Examples:</strong></p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="2 in [1, 2, 3] // true &quot;a&quot; in [&quot;b&quot;, &quot;c&quot;] // false"><pre class="notranslate"><code>2 in [1, 2, 3] // true "a" in ["b", "c"] // false </code></pre></div> <p dir="auto"><strong>size</strong> - Determine the number of elements in the list.</p> <p dir="auto"><strong>Signatures:</strong></p> <ul dir="auto"> <li><code>list.size() -&gt; int</code></li> <li><code>size(list) -&gt; int</code></li> </ul> <p dir="auto"><strong>Examples:</strong></p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="['hello', 'world'].size() // 2 size(['first', 'second', 'third']) // 3"><pre class="notranslate"><code>['hello', 'world'].size() // 2 size(['first', 'second', 'third']) // 3 </code></pre></div> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Map Operators</h4><a id="user-content-map-operators" class="anchor" aria-label="Permalink: Map Operators" href="#map-operators"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto"><strong>Map Indexing ([])</strong> - map indexing. Expected time complexity is O(1). Some implementations may not guarantee O(1) lookup times, please check with the CEL implementation to verify. In the worst case for string keys, the lookup cost could be proportional to the size of the map keys times the size of the index string.</p> <p dir="auto"><strong>Signatures:</strong></p> <ul dir="auto"> <li><code>map(A, B)[A] -&gt; B</code></li> </ul> <p dir="auto"><strong>Examples:</strong></p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="{'key1': 'value1', 'key2': 'value2'}['key1'] // 'value1' {'name': 'Bob', 'age': 42}['age'] // 42"><pre class="notranslate"><code>{'key1': 'value1', 'key2': 'value2'}['key1'] // 'value1' {'name': 'Bob', 'age': 42}['age'] // 42 </code></pre></div> <p dir="auto"><strong>Map Key Membership (in)</strong> - Checks if a key exists in a map. Expected time complexity is O(1).</p> <p dir="auto">Some implementations may not guarantee O(1) lookup times, please check with the CEL implementation to verify. In the worst case for string keys, the lookup cost could be proportional to the size of the map keys times the size of the index string.</p> <p dir="auto"><strong>Signatures:</strong></p> <ul dir="auto"> <li><code>A in map(A, B) -&gt; bool</code></li> </ul> <p dir="auto"><strong>Examples:</strong></p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="'key1' in {'key1': 'value1', 'key2': 'value2'} // true 3 in {1: &quot;one&quot;, 2: &quot;two&quot;} // false"><pre class="notranslate"><code>'key1' in {'key1': 'value1', 'key2': 'value2'} // true 3 in {1: "one", 2: "two"} // false </code></pre></div> <p dir="auto"><strong>size</strong> - Determine the number of entries in the map.</p> <p dir="auto"><strong>Signatures:</strong></p> <ul dir="auto"> <li><code>map.size() -&gt; int</code></li> <li><code>size(map) -&gt; int</code></li> </ul> <p dir="auto"><strong>Examples:</strong></p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="{'hello': 'world'}.size() // 1 size({1: true, 2: false}) // 2"><pre class="notranslate"><code>{'hello': 'world'}.size() // 1 size({1: true, 2: false}) // 2 </code></pre></div> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Bytes Functions</h4><a id="user-content-bytes-functions" class="anchor" aria-label="Permalink: Bytes Functions" href="#bytes-functions"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto"><strong>size</strong> - Determine the number of bytes in the sequence.</p> <p dir="auto"><strong>Signatures:</strong></p> <ul dir="auto"> <li><code>bytes.size() -&gt; int</code></li> <li><code>size(bytes) -&gt; int</code></li> </ul> <p dir="auto"><strong>Examples:</strong></p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="b'hello'.size() // 5 size(b'world!') // 6 size(b'\xF0\x9F\xA4\xAA') // 4"><pre class="notranslate"><code>b'hello'.size() // 5 size(b'world!') // 6 size(b'\xF0\x9F\xA4\xAA') // 4 </code></pre></div> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">String Functions</h4><a id="user-content-string-functions" class="anchor" aria-label="Permalink: String Functions" href="#string-functions"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto"><strong>contains</strong> - Tests whether the string operand contains the substring. Time complexity is proportional to the product of the sizes of the arguments.</p> <p dir="auto"><strong>Signatures:</strong></p> <ul dir="auto"> <li><code>string.contains(string) -&gt; bool</code></li> </ul> <p dir="auto"><strong>Examples:</strong></p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="&quot;hello world&quot;.contains(&quot;world&quot;) // true &quot;foobar&quot;.contains(&quot;baz&quot;) // false"><pre class="notranslate"><code>"hello world".contains("world") // true "foobar".contains("baz") // false </code></pre></div> <p dir="auto"><strong>endsWith</strong> - Tests whether the string operand ends with the specified suffix. Average time complexity is linear with respect to the size of the suffix string. Worst-case time complexity is proportional to the product of the sizes of the arguments.</p> <p dir="auto"><strong>Signatures:</strong></p> <ul dir="auto"> <li><code>string.endsWith(string) -&gt; bool</code></li> </ul> <p dir="auto"><strong>Examples:</strong></p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="&quot;hello world&quot;.endsWith(&quot;world&quot;) // true &quot;foobar&quot;.endsWith(&quot;bar&quot;) // true"><pre class="notranslate"><code>"hello world".endsWith("world") // true "foobar".endsWith("bar") // true </code></pre></div> <p dir="auto"><strong>matches</strong> - Tests whether a string matches a given RE2 regular expression. Time complexity is proportional to the product of the sizes of the arguments as guaranteed by the <a href="https://github.com/google/re2/wiki/WhyRE2">RE2 design</a>.</p> <p dir="auto"><strong>Signatures:</strong></p> <ul dir="auto"> <li><code>matches(string, string) -&gt; bool</code></li> <li><code>string.matches(string) -&gt; bool</code></li> </ul> <p dir="auto"><strong>Examples:</strong></p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="matches(&quot;foobar&quot;, &quot;foo.*&quot;) // true &quot;foobar&quot;.matches(&quot;foo.*&quot;) // true"><pre class="notranslate"><code>matches("foobar", "foo.*") // true "foobar".matches("foo.*") // true </code></pre></div> <p dir="auto"><strong>startsWith</strong> - Tests whether the string operand starts with the specified prefix. Average time complexity is linear with respect to the size of the prefix. Worst-case time complexity is proportional to the product of the sizes of the arguments.</p> <p dir="auto"><strong>Signatures:</strong></p> <ul dir="auto"> <li><code>string.startsWith(string) -&gt; bool</code></li> </ul> <p dir="auto"><strong>Examples:</strong></p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="&quot;hello world&quot;.startsWith(&quot;hello&quot;) // true &quot;foobar&quot;.startsWith(&quot;foo&quot;) // true"><pre class="notranslate"><code>"hello world".startsWith("hello") // true "foobar".startsWith("foo") // true </code></pre></div> <p dir="auto"><strong>size</strong> - Determine the length of the string in terms of the number of Unicode codepoints</p> <p dir="auto"><strong>Signatures:</strong></p> <ul dir="auto"> <li><code>string.size() -&gt; int</code></li> <li><code>size(string) -&gt; int</code></li> </ul> <p dir="auto"><strong>Examples:</strong></p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="&quot;hello&quot;.size() // 5 size(&quot;world!&quot;) // 6 &quot;fiance\u0301&quot;.size() // 7 size(string(b'\xF0\x9F\xA4\xAA')) // 1"><pre class="notranslate"><code>"hello".size() // 5 size("world!") // 6 "fiance\u0301".size() // 7 size(string(b'\xF0\x9F\xA4\xAA')) // 1 </code></pre></div> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Date/Time Functions</h4><a id="user-content-datetime-functions" class="anchor" aria-label="Permalink: Date/Time Functions" href="#datetime-functions"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">All timestamp functions which take accept a timezone argument can use any of the supported <a href="https://www.joda.org/joda-time/timezones.html" rel="nofollow">Joda Timezones</a> either using the numeric format or the geographic region.</p> <p dir="auto"><strong>getDate</strong> - Get the day of the month from a timestamp (one-based indexing).</p> <p dir="auto"><strong>Signatures:</strong></p> <ul dir="auto"> <li><code>google.protobuf.Timestamp.getDate() -&gt; int</code> (in UTC)</li> <li><code>google.protobuf.Timestamp.getDate(string) -&gt; int</code> (with timezone)</li> </ul> <p dir="auto"><strong>Examples:</strong></p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="timestamp(&quot;2023-12-25T00:00:00Z&quot;).getDate() // 25 timestamp(&quot;2023-12-25T00:00:00Z&quot;).getDate(&quot;America/Los_Angeles&quot;) // 24"><pre class="notranslate"><code>timestamp("2023-12-25T00:00:00Z").getDate() // 25 timestamp("2023-12-25T00:00:00Z").getDate("America/Los_Angeles") // 24 </code></pre></div> <p dir="auto"><strong>getDayOfMonth</strong> - Get the day of the month from a timestamp (zero-based indexing).</p> <p dir="auto"><strong>Signatures:</strong></p> <ul dir="auto"> <li><code>google.protobuf.Timestamp.getDayOfMonth() -&gt; int</code> (in UTC)</li> <li><code>google.protobuf.Timestamp.getDayOfMonth(string) -&gt; int</code> (with timezone)</li> </ul> <p dir="auto"><strong>Examples:</strong></p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="timestamp(&quot;2023-12-25T00:00:00Z&quot;).getDayOfMonth() // 24 timestamp(&quot;2023-12-25T00:00:00Z&quot;).getDayOfMonth(&quot;America/Los_Angeles&quot;) // 23"><pre class="notranslate"><code>timestamp("2023-12-25T00:00:00Z").getDayOfMonth() // 24 timestamp("2023-12-25T00:00:00Z").getDayOfMonth("America/Los_Angeles") // 23 </code></pre></div> <p dir="auto"><strong>getDayOfWeek</strong> - Get the day of the week from a timestamp (zero-based, zero for Sunday).</p> <p dir="auto"><strong>Signatures:</strong></p> <ul dir="auto"> <li><code>google.protobuf.Timestamp.getDayOfWeek() -&gt; int</code> (in UTC)</li> <li><code>google.protobuf.Timestamp.getDayOfWeek(string) -&gt; int</code> (with timezone)</li> </ul> <p dir="auto"><strong>Examples:</strong></p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="timestamp(&quot;2023-12-25T12:00:00Z&quot;).getDayOfWeek() // 1 (Monday)"><pre class="notranslate"><code>timestamp("2023-12-25T12:00:00Z").getDayOfWeek() // 1 (Monday) </code></pre></div> <p dir="auto"><strong>getDayOfYear</strong> - Get the day of the year from a timestamp (zero-based indexing).</p> <p dir="auto"><strong>Signatures:</strong></p> <ul dir="auto"> <li><code>google.protobuf.Timestamp.getDayOfYear() -&gt; int</code> (in UTC)</li> <li><code>google.protobuf.Timestamp.getDayOfYear(string) -&gt; int</code> (with timezone)</li> </ul> <p dir="auto"><strong>Examples:</strong></p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="timestamp(&quot;2023-12-25T12:00:00Z&quot;).getDayOfYear() // 358"><pre class="notranslate"><code>timestamp("2023-12-25T12:00:00Z").getDayOfYear() // 358 </code></pre></div> <p dir="auto"><strong>getFullYear</strong> - Get the year from a timestamp.</p> <p dir="auto"><strong>Signatures:</strong></p> <ul dir="auto"> <li><code>google.protobuf.Timestamp.getFullYear() -&gt; int</code> (in UTC)</li> <li><code>google.protobuf.Timestamp.getFullYear(string) -&gt; int</code> (with timezone)</li> </ul> <p dir="auto"><strong>Examples:</strong></p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="timestamp(&quot;2023-12-25T12:00:00Z&quot;).getFullYear() // 2023"><pre class="notranslate"><code>timestamp("2023-12-25T12:00:00Z").getFullYear() // 2023 </code></pre></div> <p dir="auto"><strong>getHours</strong> - Get the hour from a timestamp or convert the duration to hours</p> <p dir="auto"><strong>Signatures:</strong></p> <ul dir="auto"> <li><code>google.protobuf.Timestamp.getHours() -&gt; int</code> (in UTC)</li> <li><code>google.protobuf.Timestamp.getHours(string) -&gt; int</code> (with timezone)</li> <li><code>google.protobuf.Duration.getHours() -&gt; int</code> convert the duration to hours</li> </ul> <p dir="auto"><strong>Examples:</strong></p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="timestamp(&quot;2023-12-25T12:00:00Z&quot;).getHours() // 12 duration(&quot;3h&quot;).getHours() // 3"><pre class="notranslate"><code>timestamp("2023-12-25T12:00:00Z").getHours() // 12 duration("3h").getHours() // 3 </code></pre></div> <p dir="auto"><strong>getMilliseconds</strong> - Get the milliseconds from a timestamp or the milliseconds portion of the duration</p> <p dir="auto"><strong>Signatures:</strong></p> <ul dir="auto"> <li><code>google.protobuf.Timestamp.getMilliseconds() -&gt; int</code> obtain the milliseconds component of the timestamp in UTC.</li> <li><code>google.protobuf.Timestamp.getMilliseconds(string) -&gt; int</code> obtain the milliseconds component with a timezone.</li> <li><code>google.protobuf.Duration.getMilliseconds() -&gt; int</code> obtain the milliseconds portion of the duration value. Other time unit functions convert the duration to that format; however, this method does not.</li> </ul> <p dir="auto"><strong>Examples:</strong></p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="timestamp(&quot;2023-12-25T12:00:00.500Z&quot;).getMilliseconds() // 500 duration(&quot;1.234s&quot;).getMilliseconds() // 234"><pre class="notranslate"><code>timestamp("2023-12-25T12:00:00.500Z").getMilliseconds() // 500 duration("1.234s").getMilliseconds() // 234 </code></pre></div> <p dir="auto"><strong>getMinutes</strong> - Get the minutes from a timestamp or convert a duration to minutes</p> <p dir="auto"><strong>Signatures:</strong></p> <ul dir="auto"> <li><code>google.protobuf.Timestamp.getMinutes() -&gt; int</code> get the minutes component of a timestamp in UTC.</li> <li><code>google.protobuf.Timestamp.getMinutes(string) -&gt; int</code> get the minutes component of a timestamp within a given timezone.</li> <li><code>google.protobuf.Duration.getMinutes() -&gt; int</code> convert the duration to minutes.</li> </ul> <p dir="auto"><strong>Examples:</strong></p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="timestamp(&quot;2023-12-25T12:30:00Z&quot;).getMinutes() // 30 duration(&quot;1h30m&quot;).getMinutes() // 90"><pre class="notranslate"><code>timestamp("2023-12-25T12:30:00Z").getMinutes() // 30 duration("1h30m").getMinutes() // 90 </code></pre></div> <p dir="auto"><strong>getMonth</strong> - Get the month from a timestamp (zero-based, 0 for January).</p> <p dir="auto"><strong>Signatures:</strong></p> <ul dir="auto"> <li><code>google.protobuf.Timestamp.getMonth() -&gt; int</code> (in UTC)</li> <li><code>google.protobuf.Timestamp.getMonth(string) -&gt; int</code> (with timezone)</li> </ul> <p dir="auto"><strong>Examples:</strong></p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="timestamp(&quot;2023-12-25T12:00:00Z&quot;).getMonth() // 11 (December)"><pre class="notranslate"><code>timestamp("2023-12-25T12:00:00Z").getMonth() // 11 (December) </code></pre></div> <p dir="auto"><strong>getSeconds</strong> - Get the seconds from a timestamp or convert the duration to seconds</p> <p dir="auto"><strong>Signatures:</strong></p> <ul dir="auto"> <li><code>google.protobuf.Timestamp.getSeconds() -&gt; int</code> get the seconds component of the timestamp in UTC.</li> <li><code>google.protobuf.Timestamp.getSeconds(string) -&gt; int</code> get the seconds component of the timestamp with a provided timezone.</li> <li><code>google.protobuf.Duration.getSeconds() -&gt; int</code> convert the duration to seconds.</li> </ul> <p dir="auto"><strong>Examples:</strong></p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="timestamp(&quot;2023-12-25T12:30:30Z&quot;).getSeconds() // 30 duration(&quot;1m30s&quot;).getSeconds() // 90"><pre class="notranslate"><code>timestamp("2023-12-25T12:30:30Z").getSeconds() // 30 duration("1m30s").getSeconds() // 90 </code></pre></div> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Types and Conversions</h4><a id="user-content-types-and-conversions" class="anchor" aria-label="Permalink: Types and Conversions" href="#types-and-conversions"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto"><strong>bool</strong> <code>type(bool)</code> - Type denotation</p> <p dir="auto"><strong>Signatures:</strong></p> <ul dir="auto"> <li><code>bool(bool) -&gt; bool</code> (identity)</li> <li><code>bool(string) -&gt; bool</code> (type conversion)</li> </ul> <p dir="auto"><strong>Examples:</strong></p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="bool(true) // true bool(&quot;true&quot;) // true bool(&quot;FALSE&quot;) // false"><pre class="notranslate"><code>bool(true) // true bool("true") // true bool("FALSE") // false </code></pre></div> <p dir="auto"><strong>bytes</strong> <code>type(bytes)</code> - Type denotation</p> <p dir="auto"><strong>Signatures:</strong></p> <ul dir="auto"> <li><code>bytes(bytes) -&gt; bytes</code> (identity)</li> <li><code>bytes(string) -&gt; bytes</code> (type conversion)</li> </ul> <p dir="auto"><strong>Examples:</strong></p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="bytes(&quot;hello&quot;) // b'hello' bytes(&quot;🤪&quot;) // b'\xF0\x9F\xA4\xAA'"><pre class="notranslate"><code>bytes("hello") // b'hello' bytes("🤪") // b'\xF0\x9F\xA4\xAA' </code></pre></div> <p dir="auto"><strong>double</strong> <code>type(double)</code> - Type denotation</p> <p dir="auto"><strong>Signatures:</strong></p> <ul dir="auto"> <li><code>double(double) -&gt; double</code> (identity)</li> <li><code>double(int) -&gt; double</code> (type conversion)</li> <li><code>double(uint) -&gt; double</code> (type conversion)</li> <li><code>double(string) -&gt; double</code> (type conversion)</li> </ul> <p dir="auto"><strong>Examples:</strong></p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="double(3.14) // 3.14 double(10) // 10.0 double(&quot;3.14&quot;) // 3.14 (if successful, otherwise an error)"><pre class="notranslate"><code>double(3.14) // 3.14 double(10) // 10.0 double("3.14") // 3.14 (if successful, otherwise an error) </code></pre></div> <p dir="auto"><strong>duration</strong></p> <p dir="auto"><strong>Signatures:</strong></p> <ul dir="auto"> <li><code>duration(google.protobuf.Duration) -&gt; google.protobuf.Duration</code></li> <li><code>duration(string) -&gt; google.protobuf.Duration</code></li> </ul> <p dir="auto"><strong>Examples:</strong></p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="duration(&quot;1h30m&quot;) // google.protobuf.Duration representing 1 hour and 30 minutes"><pre class="notranslate"><code>duration("1h30m") // google.protobuf.Duration representing 1 hour and 30 minutes </code></pre></div> <p dir="auto"><strong>dyn</strong> <code>type(dyn)</code> - Type denotation</p> <p dir="auto">The <code>dyn</code> types does not exist at runtime, but provides a hint to the type-checker to disable strong type agreement checks.</p> <p dir="auto"><strong>Signatures:</strong></p> <ul dir="auto"> <li><code>dyn(A) -&gt; dyn</code> (type conversion) (where A is any type)</li> </ul> <p dir="auto"><strong>Examples:</strong></p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="dyn(123) // integer 123 marked `dyn` during type-checking dyn(&quot;hello&quot;) // string &quot;hello&quot; marked `dyn` during type-checking"><pre class="notranslate"><code>dyn(123) // integer 123 marked `dyn` during type-checking dyn("hello") // string "hello" marked `dyn` during type-checking </code></pre></div> <p dir="auto"><strong>int</strong> <code>type(int)</code> - Type denotation</p> <p dir="auto"><strong>Signatures:</strong></p> <ul dir="auto"> <li><code>int(int) -&gt; int</code> (identity)</li> <li><code>int(uint) -&gt; int</code> (type conversion)</li> <li><code>int(double) -&gt; int</code> (type conversion, rounds toward zero, errors if out of range)</li> <li><code>int(string) -&gt; int</code> (type conversion)</li> <li><code>int(enum E) -&gt; int</code> (type conversion)</li> <li><code>int(google.protobuf.Timestamp) -&gt; int</code> converts to seconds since Unix epoch</li> </ul> <p dir="auto"><strong>Examples:</strong></p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="int(123) // 123 int(3.14) // 3 int(&quot;123&quot;) // 123 (if successful, otherwise an error)"><pre class="notranslate"><code>int(123) // 123 int(3.14) // 3 int("123") // 123 (if successful, otherwise an error) </code></pre></div> <p dir="auto"><strong>list</strong> <code>type(list(dyn))</code> - Type denotation</p> <p dir="auto"><strong>map</strong> <code>type(map(dyn, dyn))</code> - Type denotation</p> <p dir="auto"><strong>null_type</strong> <code>type(null)</code> - Type denotation</p> <p dir="auto"><strong>string</strong> <code>type(string)</code> - Type denotation</p> <p dir="auto"><strong>Signatures:</strong></p> <ul dir="auto"> <li><code>string(string) -&gt; string</code> (identity)</li> <li><code>string(bool) -&gt; string</code> converts <code>true</code> to <code>"true"</code> and <code>false</code> to <code>"false"</code></li> <li><code>string(int) -&gt; string</code> converts integer values to base 10 representation</li> <li><code>string(uint) -&gt; string</code> converts unsigned integer values to base 10 representation</li> <li><code>string(double) -&gt; string</code> converts a double to a string</li> <li><code>string(bytes) -&gt; string</code> converts a byte sequence to a UTF-8 string, errors for invalid code points</li> <li><code>string(timestamp) -&gt; string</code> converts a timestamp value to <a href="https://datatracker.ietf.org/doc/html/rfc3339" rel="nofollow">RFC3339</a> format</li> <li><code>string(duration) -&gt; string</code> converts a duration value to seconds and fractional seconds with an 's' suffix</li> </ul> <p dir="auto"><strong>Examples:</strong></p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="string(123) // &quot;123&quot; string(123u) // &quot;123u&quot; string(3.14) // &quot;3.14&quot; string(b'hello') // &quot;hello&quot; string(b'\xf0\x9f\xa4\xaa') // &quot;🤪&quot; string(duration('1m1ms')) // &quot;60.001s&quot;"><pre class="notranslate"><code>string(123) // "123" string(123u) // "123u" string(3.14) // "3.14" string(b'hello') // "hello" string(b'\xf0\x9f\xa4\xaa') // "🤪" string(duration('1m1ms')) // "60.001s" </code></pre></div> <p dir="auto"><strong>timestamp</strong></p> <p dir="auto"><strong>Signatures:</strong></p> <ul dir="auto"> <li><code>timestamp(google.protobuf.Timestamp) -&gt; google.protobuf.Timestamp</code> (identity)</li> <li><code>timestamp(string) -&gt; google.protobuf.Timestamp</code> (type conversion, according to RFC3339)</li> </ul> <p dir="auto"><strong>Examples:</strong></p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="// google.protobuf.Timestamp representing August 26, 2023 at 12:39 PM PDT timestamp(&quot;2023-08-26T12:39:00-07:00&quot;)"><pre class="notranslate"><code>// google.protobuf.Timestamp representing August 26, 2023 at 12:39 PM PDT timestamp("2023-08-26T12:39:00-07:00") </code></pre></div> <p dir="auto"><strong>type</strong> <code>type</code> - Type denotation</p> <p dir="auto"><strong>Signatures:</strong></p> <ul dir="auto"> <li><code>type(A) -&gt; type</code> (returns the type of the value, where A is any type)</li> </ul> <p dir="auto"><strong>Examples:</strong></p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="type(123) // int type(&quot;hello&quot;) // string"><pre class="notranslate"><code>type(123) // int type("hello") // string </code></pre></div> <p dir="auto"><strong>uint</strong> <code>type(uint)</code> - Type denotation</p> <p dir="auto"><strong>Signatures:</strong></p> <ul dir="auto"> <li><code>uint(uint) -&gt; uint</code> (identity)</li> <li><code>uint(int) -&gt; uint</code> (type conversion)</li> <li><code>uint(double) -&gt; uint</code> (type conversion, rounds toward zero, errors if out of range)</li> <li><code>uint(string) -&gt; uint</code> (type conversion)</li> </ul> <p dir="auto"><strong>Examples:</strong></p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="uint(123) // 123u uint(3.14) // 3u uint(&quot;123&quot;) // 123u (if successful, otherwise an error)"><pre class="notranslate"><code>uint(123) // 123u uint(3.14) // 3u uint("123") // 123u (if successful, otherwise an error) </code></pre></div> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Appendix 1: Legacy Behavior</h2><a id="user-content-appendix-1-legacy-behavior" class="anchor" aria-label="Permalink: Appendix 1: Legacy Behavior" href="#appendix-1-legacy-behavior"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Homogeneous Equality</h3><a id="user-content-homogeneous-equality" class="anchor" aria-label="Permalink: Homogeneous Equality" href="#homogeneous-equality"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Prior to cel-spec v0.7.0, CEL runtimes only supported homogeneous equality to be consistent with the homogeneous equality defined by the type-checker. The original runtime definition for equality is as follows:</p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="Equality and inequality are homogeneous; comparing values of different runtime types results in a runtime error. Thus `2 == 3` is `false`, but `2 == 2.0` is an error. For `double`, all not-a-number (`NaN`) values compare equal. This is different than the usual semantics of floating-point numbers, but it is more consistent with the usual expectations of reflexivity, and is more compatible with the usual notions of equality on protocol buffers."><pre class="notranslate"><code>Equality and inequality are homogeneous; comparing values of different runtime types results in a runtime error. Thus `2 == 3` is `false`, but `2 == 2.0` is an error. For `double`, all not-a-number (`NaN`) values compare equal. This is different than the usual semantics of floating-point numbers, but it is more consistent with the usual expectations of reflexivity, and is more compatible with the usual notions of equality on protocol buffers. </code></pre></div> </article></div><button hidden=""></button></section></div></div></div> <!-- --> <!-- --> </div></div></div><div class="Box-sc-g0xbh4-0"></div></div></div></div></div><div id="find-result-marks-container" class="Box-sc-g0xbh4-0 cCoXib"></div><button hidden="" data-testid="" data-hotkey-scope="read-only-cursor-text-area"></button><button hidden=""></button></div> <!-- --> <!-- --> <script type="application/json" id="__PRIMER_DATA_:R0:__">{"resolvedServerColorMode":"day"}</script></div> </react-app> </turbo-frame> </div> </turbo-frame> </main> </div> </div> <footer class="footer pt-8 pb-6 f6 color-fg-muted p-responsive" role="contentinfo" > <h2 class='sr-only'>Footer</h2> <div class="d-flex flex-justify-center flex-items-center flex-column-reverse flex-lg-row flex-wrap flex-lg-nowrap"> <div class="d-flex flex-items-center flex-shrink-0 mx-2"> <a aria-label="Homepage" title="GitHub" class="footer-octicon mr-2" href="https://github.com"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-mark-github"> <path d="M12.5.75C6.146.75 1 5.896 1 12.25c0 5.089 3.292 9.387 7.863 10.91.575.101.79-.244.79-.546 0-.273-.014-1.178-.014-2.142-2.889.532-3.636-.704-3.866-1.35-.13-.331-.69-1.352-1.18-1.625-.402-.216-.977-.748-.014-.762.906-.014 1.553.834 1.769 1.179 1.035 1.74 2.688 1.25 3.349.948.1-.747.402-1.25.733-1.538-2.559-.287-5.232-1.279-5.232-5.678 0-1.25.445-2.285 1.178-3.09-.115-.288-.517-1.467.115-3.048 0 0 .963-.302 3.163 1.179.92-.259 1.897-.388 2.875-.388.977 0 1.955.13 2.875.388 2.2-1.495 3.162-1.179 3.162-1.179.633 1.581.23 2.76.115 3.048.733.805 1.179 1.825 1.179 3.09 0 4.413-2.688 5.39-5.247 5.678.417.36.776 1.05.776 2.128 0 1.538-.014 2.774-.014 3.162 0 .302.216.662.79.547C20.709 21.637 24 17.324 24 12.25 24 5.896 18.854.75 12.5.75Z"></path> </svg> </a> <span> &copy; 2025 GitHub,&nbsp;Inc. </span> </div> <nav aria-label="Footer"> <h3 class="sr-only" id="sr-footer-heading">Footer navigation</h3> <ul class="list-style-none d-flex flex-justify-center flex-wrap mb-2 mb-lg-0" aria-labelledby="sr-footer-heading"> <li class="mx-2"> <a data-analytics-event="{&quot;category&quot;:&quot;Footer&quot;,&quot;action&quot;:&quot;go to Terms&quot;,&quot;label&quot;:&quot;text:terms&quot;}" href="https://docs.github.com/site-policy/github-terms/github-terms-of-service" data-view-component="true" class="Link--secondary Link">Terms</a> </li> <li class="mx-2"> <a data-analytics-event="{&quot;category&quot;:&quot;Footer&quot;,&quot;action&quot;:&quot;go to privacy&quot;,&quot;label&quot;:&quot;text:privacy&quot;}" href="https://docs.github.com/site-policy/privacy-policies/github-privacy-statement" data-view-component="true" class="Link--secondary Link">Privacy</a> </li> <li class="mx-2"> <a data-analytics-event="{&quot;category&quot;:&quot;Footer&quot;,&quot;action&quot;:&quot;go to security&quot;,&quot;label&quot;:&quot;text:security&quot;}" href="https://github.com/security" data-view-component="true" class="Link--secondary Link">Security</a> </li> <li class="mx-2"> <a data-analytics-event="{&quot;category&quot;:&quot;Footer&quot;,&quot;action&quot;:&quot;go to status&quot;,&quot;label&quot;:&quot;text:status&quot;}" href="https://www.githubstatus.com/" data-view-component="true" class="Link--secondary Link">Status</a> </li> <li class="mx-2"> <a data-analytics-event="{&quot;category&quot;:&quot;Footer&quot;,&quot;action&quot;:&quot;go to docs&quot;,&quot;label&quot;:&quot;text:docs&quot;}" href="https://docs.github.com/" data-view-component="true" class="Link--secondary Link">Docs</a> </li> <li class="mx-2"> <a data-analytics-event="{&quot;category&quot;:&quot;Footer&quot;,&quot;action&quot;:&quot;go to contact&quot;,&quot;label&quot;:&quot;text:contact&quot;}" href="https://support.github.com?tags=dotcom-footer" data-view-component="true" class="Link--secondary Link">Contact</a> </li> <li class="mx-2" > <cookie-consent-link> <button type="button" class="Link--secondary underline-on-hover border-0 p-0 color-bg-transparent" data-action="click:cookie-consent-link#showConsentManagement" data-analytics-event="{&quot;location&quot;:&quot;footer&quot;,&quot;action&quot;:&quot;cookies&quot;,&quot;context&quot;:&quot;subfooter&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;cookies_link_subfooter_footer&quot;}" > Manage cookies </button> </cookie-consent-link> </li> <li class="mx-2"> <cookie-consent-link> <button type="button" class="Link--secondary underline-on-hover border-0 p-0 color-bg-transparent" data-action="click:cookie-consent-link#showConsentManagement" data-analytics-event="{&quot;location&quot;:&quot;footer&quot;,&quot;action&quot;:&quot;dont_share_info&quot;,&quot;context&quot;:&quot;subfooter&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;dont_share_info_link_subfooter_footer&quot;}" > Do not share my personal information </button> </cookie-consent-link> </li> </ul> </nav> </div> </footer> <ghcc-consent id="ghcc" class="position-fixed bottom-0 left-0" style="z-index: 999999" data-initial-cookie-consent-allowed="" data-cookie-consent-required="false"></ghcc-consent> <div id="ajax-error-message" class="ajax-error-message flash flash-error" hidden> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-alert"> <path d="M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path> </svg> <button type="button" class="flash-close js-ajax-error-dismiss" aria-label="Dismiss error"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-x"> <path d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l3.22 3.22a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-3.22 3.22a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z"></path> </svg> </button> You can’t perform that action at this time. </div> <template id="site-details-dialog"> <details class="details-reset details-overlay details-overlay-dark lh-default color-fg-default hx_rsm" open> <summary role="button" aria-label="Close dialog"></summary> <details-dialog class="Box Box--overlay d-flex flex-column anim-fade-in fast hx_rsm-dialog hx_rsm-modal"> <button class="Box-btn-octicon m-0 btn-octicon position-absolute right-0 top-0" type="button" aria-label="Close dialog" data-close-dialog> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-x"> <path d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l3.22 3.22a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-3.22 3.22a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z"></path> </svg> </button> <div class="octocat-spinner my-6 js-details-dialog-spinner"></div> </details-dialog> </details> </template> <div class="Popover js-hovercard-content position-absolute" style="display: none; outline: none;"> <div class="Popover-message Popover-message--bottom-left Popover-message--large Box color-shadow-large" style="width:360px;"> </div> </div> <template id="snippet-clipboard-copy-button"> <div class="zeroclipboard-container position-absolute right-0 top-0"> <clipboard-copy aria-label="Copy" class="ClipboardButton btn js-clipboard-copy m-2 p-0" data-copy-feedback="Copied!" data-tooltip-direction="w"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-copy js-clipboard-copy-icon m-2"> <path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path><path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path> </svg> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-check js-clipboard-check-icon color-fg-success d-none m-2"> <path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"></path> </svg> </clipboard-copy> </div> </template> <template id="snippet-clipboard-copy-button-unpositioned"> <div class="zeroclipboard-container"> <clipboard-copy aria-label="Copy" class="ClipboardButton btn btn-invisible js-clipboard-copy m-2 p-0 d-flex flex-justify-center flex-items-center" data-copy-feedback="Copied!" data-tooltip-direction="w"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-copy js-clipboard-copy-icon"> <path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path><path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path> </svg> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-check js-clipboard-check-icon color-fg-success d-none"> <path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"></path> </svg> </clipboard-copy> </div> </template> </div> <div id="js-global-screen-reader-notice" class="sr-only mt-n1" aria-live="polite" aria-atomic="true" ></div> <div id="js-global-screen-reader-notice-assertive" class="sr-only mt-n1" aria-live="assertive" aria-atomic="true"></div> </body> </html>

Pages: 1 2 3 4 5 6 7 8 9 10