Add add-license scripts
diff --git a/.gitignore b/.gitignore
index c37e68c..f4cc52b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,3 +13,4 @@
 *.iws
 *.swp
 out
+!etc/bin
diff --git a/etc/bin/add-license-adoc.groovy b/etc/bin/add-license-adoc.groovy
new file mode 100644
index 0000000..c7a13b1
--- /dev/null
+++ b/etc/bin/add-license-adoc.groovy
@@ -0,0 +1,60 @@
+#!/usr/bin/env groovy
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    https://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+import java.nio.file.*
+
+def ASF_MARKER = "Licensed to the Apache Software Foundation (ASF) under one"
+def HEADER = '''////
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+////
+
+'''
+
+def root = Paths.get(".").toRealPath()
+
+Files.walk(root)
+        .filter { path -> Files.isRegularFile(path) && path.toString().endsWith(".adoc") }
+        .each { path ->
+            def text = path.toFile().getText("UTF-8")
+            if (!text.contains(ASF_MARKER)) {
+                println "📄 Adding ASF header to ${path}"
+                // Prepend header + existing content
+                path.toFile().withWriter("UTF-8") { writer ->
+                    writer << HEADER
+                    writer << text
+                }
+            }
+        }
+
+println "✅ Done."
diff --git a/etc/bin/add-license-css.groovy b/etc/bin/add-license-css.groovy
new file mode 100644
index 0000000..d394fd5
--- /dev/null
+++ b/etc/bin/add-license-css.groovy
@@ -0,0 +1,60 @@
+#!/usr/bin/env groovy
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    https://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+import java.nio.file.*
+
+def ASF_MARKER = "Licensed to the Apache Software Foundation (ASF) under one"
+def HEADER = '''/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    https://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+'''
+
+def root = Paths.get(".").toRealPath()
+
+Files.walk(root)
+        .filter { path -> Files.isRegularFile(path) && path.toString().endsWith(".css") }
+        .each { path ->
+            def text = path.toFile().getText("UTF-8")
+            if (!text.contains(ASF_MARKER)) {
+                println "📄 Adding ASF header to ${path}"
+                // Prepend header + existing content
+                path.toFile().withWriter("UTF-8") { writer ->
+                    writer << HEADER
+                    writer << text
+                }
+            }
+        }
+
+println "✅ Done."
diff --git a/etc/bin/add-license-gradle.groovy b/etc/bin/add-license-gradle.groovy
new file mode 100644
index 0000000..c4a4fed
--- /dev/null
+++ b/etc/bin/add-license-gradle.groovy
@@ -0,0 +1,60 @@
+#!/usr/bin/env groovy
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    https://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+import java.nio.file.*
+
+def ASF_MARKER = "Licensed to the Apache Software Foundation (ASF) under one"
+def HEADER = '''/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    https://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+'''
+
+def root = Paths.get(".").toRealPath()
+
+Files.walk(root)
+        .filter { path -> Files.isRegularFile(path) && path.toString().endsWith(".gradle") }
+        .each { path ->
+            def text = path.toFile().getText("UTF-8")
+            if (!text.contains(ASF_MARKER)) {
+                println "📄 Adding ASF header to ${path}"
+                // Prepend header + existing content
+                path.toFile().withWriter("UTF-8") { writer ->
+                    writer << HEADER
+                    writer << text
+                }
+            }
+        }
+
+println "✅ Done."
diff --git a/etc/bin/add-license-groovy-java.groovy b/etc/bin/add-license-groovy-java.groovy
new file mode 100644
index 0000000..ef2dccb
--- /dev/null
+++ b/etc/bin/add-license-groovy-java.groovy
@@ -0,0 +1,62 @@
+#!/usr/bin/env groovy
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    https://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+import java.nio.file.*
+
+def ASF_MARKER = "Licensed to the Apache Software Foundation (ASF) under one"
+def ASF_MARKER2 = "Licensed under the Apache License, Version 2.0 (the \"License\");"
+
+def HEADER = '''/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    https://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+'''
+
+def root = Paths.get(".").toRealPath()
+
+Files.walk(root)
+        .filter { path -> Files.isRegularFile(path) && (path.toString().endsWith(".groovy") || path.toString().endsWith(".java")) }
+        .each { path ->
+            def text = path.toFile().getText("UTF-8")
+            if (!text.contains(ASF_MARKER) && !text.contains(ASF_MARKER2)) {
+                println "📄 Adding ASF header to ${path}"
+                // Prepend header + existing content
+                path.toFile().withWriter("UTF-8") { writer ->
+                    writer << HEADER
+                    writer << text
+                }
+            }
+        }
+
+println "✅ Done."
diff --git a/etc/bin/add-license-gson.groovy b/etc/bin/add-license-gson.groovy
new file mode 100644
index 0000000..1cd03ce
--- /dev/null
+++ b/etc/bin/add-license-gson.groovy
@@ -0,0 +1,60 @@
+#!/usr/bin/env groovy
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    https://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+import java.nio.file.*
+
+def ASF_MARKER = "Licensed to the Apache Software Foundation (ASF) under one"
+def HEADER = '''/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    https://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+'''
+
+def root = Paths.get(".").toRealPath()
+
+Files.walk(root)
+        .filter { path -> Files.isRegularFile(path) && path.toString().endsWith(".gson") }
+        .each { path ->
+            def text = path.toFile().getText("UTF-8")
+            if (!text.contains(ASF_MARKER)) {
+                println "📄 Adding ASF header to ${path}"
+                // Prepend header + existing content
+                path.toFile().withWriter("UTF-8") { writer ->
+                    writer << HEADER
+                    writer << text
+                }
+            }
+        }
+
+println "✅ Done."
diff --git a/etc/bin/add-license-gsp.groovy b/etc/bin/add-license-gsp.groovy
new file mode 100644
index 0000000..b931996
--- /dev/null
+++ b/etc/bin/add-license-gsp.groovy
@@ -0,0 +1,68 @@
+#!/usr/bin/env groovy
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    https://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+import java.nio.file.*
+
+def ASF_MARKER = "Licensed under the Apache License, Version 2.0 (the \"License\")"
+def HEADER = '''<%--
+  ~  Licensed to the Apache Software Foundation (ASF) under one
+  ~  or more contributor license agreements.  See the NOTICE file
+  ~  distributed with this work for additional information
+  ~  regarding copyright ownership.  The ASF licenses this file
+  ~  to you under the Apache License, Version 2.0 (the
+  ~  "License"); you may not use this file except in compliance
+  ~  with the License.  You may obtain a copy of the License at
+  ~
+  ~    https://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~  Unless required by applicable law or agreed to in writing,
+  ~  software distributed under the License is distributed on an
+  ~  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~  KIND, either express or implied.  See the License for the
+  ~  specific language governing permissions and limitations
+  ~  under the License.
+  --%>
+'''
+
+def root = Paths.get(".").toRealPath()
+
+Files.walk(root)
+        .filter { path -> Files.isRegularFile(path) && path.toString().endsWith(".gsp") }
+        .each { path ->
+            def text = path.toFile().getText('UTF-8')
+            if (!text.contains(ASF_MARKER)) {
+                println "📄 Adding ASF header to ${path}"
+                // Prepend header + existing content
+                path.toFile().withWriter('UTF-8') { writer ->
+                    if(text.startsWith("<%@ page")) {
+                        String[] split = text.split('\n')
+                        writer << split.first()
+                        writer << '\n'
+                        writer << HEADER
+                        writer << split.tail().join("\n")
+                    }
+                    else {
+                        writer << HEADER
+                        writer << text
+                    }
+                }
+            }
+        }
+
+println "✅ Done."
diff --git a/etc/bin/add-license-js.groovy b/etc/bin/add-license-js.groovy
new file mode 100644
index 0000000..3d1f728
--- /dev/null
+++ b/etc/bin/add-license-js.groovy
@@ -0,0 +1,60 @@
+#!/usr/bin/env groovy
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    https://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+import java.nio.file.*
+
+def ASF_MARKER = "Licensed to the Apache Software Foundation (ASF) under one"
+def HEADER = '''/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    https://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+'''
+
+def root = Paths.get(".").toRealPath()
+
+Files.walk(root)
+        .filter { path -> Files.isRegularFile(path) && path.toString().endsWith(".js") }
+        .each { path ->
+            def text = path.toFile().getText("UTF-8")
+            if (!text.contains(ASF_MARKER)) {
+                println "📄 Adding ASF header to ${path}"
+                // Prepend header + existing content
+                path.toFile().withWriter("UTF-8") { writer ->
+                    writer << HEADER
+                    writer << text
+                }
+            }
+        }
+
+println "✅ Done."
diff --git a/etc/bin/add-license-md.groovy b/etc/bin/add-license-md.groovy
new file mode 100644
index 0000000..78d0210
--- /dev/null
+++ b/etc/bin/add-license-md.groovy
@@ -0,0 +1,57 @@
+#!/usr/bin/env groovy
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    https://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+import java.nio.file.*
+
+def ASF_MARKER = "Licensed under the Apache License, Version 2.0 (the \"License\")"
+def HEADER = '''<!--
+SPDX-License-Identifier: Apache-2.0
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+'''
+
+def root = Paths.get(".").toRealPath()
+
+Files.walk(root)
+        .filter { path -> Files.isRegularFile(path) && path.toString().endsWith(".md") }
+        .each { path ->
+            def text = path.toFile().getText("UTF-8")
+            if (!text.contains(ASF_MARKER)) {
+                println "📄 Adding ASF header to ${path}"
+                // Prepend header + existing content
+                path.toFile().withWriter("UTF-8") { writer ->
+                    writer << HEADER
+                    writer << text
+                }
+            }
+        }
+
+println "✅ Done."
diff --git a/etc/bin/add-license-properties.groovy b/etc/bin/add-license-properties.groovy
new file mode 100644
index 0000000..b7fec71
--- /dev/null
+++ b/etc/bin/add-license-properties.groovy
@@ -0,0 +1,59 @@
+#!/usr/bin/env groovy
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    https://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+import java.nio.file.*
+
+def ASF_MARKER = "Licensed to the Apache Software Foundation (ASF) under one"
+def HEADER = '''#
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#    https://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing,
+#  software distributed under the License is distributed on an
+#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+#  KIND, either express or implied.  See the License for the
+#  specific language governing permissions and limitations
+#  under the License.
+#
+'''
+
+def root = Paths.get(".").toRealPath()
+
+Files.walk(root)
+        .filter { path -> Files.isRegularFile(path) && path.toString().endsWith(".properties") }
+        .each { path ->
+            def text = path.toFile().getText("UTF-8")
+            if (!text.contains(ASF_MARKER)) {
+                println "📄 Adding ASF header to ${path}"
+                // Prepend header + existing content
+                path.toFile().withWriter("UTF-8") { writer ->
+                    writer << HEADER
+                    writer << text
+                }
+            }
+        }
+
+println "✅ Done."
diff --git a/etc/bin/add-license-raw.groovy b/etc/bin/add-license-raw.groovy
new file mode 100644
index 0000000..61f5f06
--- /dev/null
+++ b/etc/bin/add-license-raw.groovy
@@ -0,0 +1,60 @@
+#!/usr/bin/env groovy
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    https://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+import java.nio.file.*
+
+def ASF_MARKER = "Licensed to the Apache Software Foundation (ASF) under one"
+def HEADER = '''@*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+*@
+
+'''
+
+def root = Paths.get(".").toRealPath()
+
+Files.walk(root)
+        .filter { path -> Files.isRegularFile(path) && path.toString().endsWith(".raw") }
+        .each { path ->
+            def text = path.toFile().getText("UTF-8")
+            if (!text.contains(ASF_MARKER)) {
+                println "📄 Adding ASF header to ${path}"
+                // Prepend header + existing content
+                path.toFile().withWriter("UTF-8") { writer ->
+                    writer << HEADER
+                    writer << text
+                }
+            }
+        }
+
+println "✅ Done."
diff --git a/etc/bin/add-license-yml.groovy b/etc/bin/add-license-yml.groovy
new file mode 100644
index 0000000..ba92319
--- /dev/null
+++ b/etc/bin/add-license-yml.groovy
@@ -0,0 +1,56 @@
+#!/usr/bin/env groovy
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    https://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+import java.nio.file.*
+
+def ASF_MARKER = "Licensed to the Apache Software Foundation (ASF) under one"
+def HEADER = '''# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+'''
+
+def root = Paths.get(".").toRealPath()
+
+Files.walk(root)
+        .filter { path -> Files.isRegularFile(path) && path.toString().endsWith(".yml") }
+        .each { path ->
+            def text = path.toFile().getText("UTF-8")
+            if (!text.contains(ASF_MARKER)) {
+                println "📄 Adding ASF header to ${path}"
+                // Prepend header + existing content
+                path.toFile().withWriter("UTF-8") { writer ->
+                    writer << HEADER
+                    writer << text
+                }
+            }
+        }
+
+println "✅ Done."