diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 737cd75..886381f 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -61,7 +61,7 @@ jobs: sudo sealos version - name: build run: | - go run gen/gen.go ghcr.io/${{ github.repository_owner }}/automq-operator:latest && make info + go run gen/version/gen.go ghcr.io/${{ github.repository_owner }}/automq-operator:latest && make info cd deploy IMAGE_NAME="ghcr.io/${{ github.repository_owner }}/automq-operator-sealos:latest" sudo sealos build -t "${IMAGE_NAME}"-amd64 --platform linux/amd64 . && sudo rm -rf registry diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index bbd0f0b..9d3aaf0 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -76,6 +76,6 @@ jobs: sudo sealos version - name: build run: | - go run gen/gen.go ghcr.io/${{ github.repository_owner }}/automq-operator:latest && make info + go run gen/version/gen.go ghcr.io/${{ github.repository_owner }}/automq-operator:latest && make info cd deploy sudo sealos build -t ghcr.io/${{ github.repository_owner }}/automq-operator-sealos:latest . diff --git a/.github/workflows/update_version_config.yml b/.github/workflows/update_version_config.yml index 970a255..9e2de5a 100644 --- a/.github/workflows/update_version_config.yml +++ b/.github/workflows/update_version_config.yml @@ -21,7 +21,7 @@ jobs: vPrefix = true releaseBranch = main versionFile = .tagpr - command = go run gen/gen.go ghcr.io/${{ github.repository_owner }}/automq-operator:${{ github.event.inputs.version }} && make info + command = go run gen/version/gen.go ghcr.io/${{ github.repository_owner }}/automq-operator:${{ github.event.inputs.version }} && make info release = false changelog = true EOF diff --git a/.tagpr b/.tagpr index 4abaf75..11e1299 100644 --- a/.tagpr +++ b/.tagpr @@ -2,6 +2,6 @@ vPrefix = true releaseBranch = main versionFile = .tagpr - command = go run gen/gen.go ghcr.io/cuisongliu/automq-operator:v0.0.4 && make info + command = go run gen/version/gen.go ghcr.io/cuisongliu/automq-operator:v0.0.4 && make info release = false changelog = true diff --git a/Makefile b/Makefile index 402e9ae..cd35376 100644 --- a/Makefile +++ b/Makefile @@ -171,3 +171,7 @@ info: .PHONY: e2e e2e: fmt vet envtest ## Run tests. KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test ./e2e/... --ginkgo.v -v --ginkgo.trace + + +bindata: + go run gen/bindata/main.go diff --git a/defaults/up.sh b/defaults/up.sh new file mode 100644 index 0000000..d33ebb4 --- /dev/null +++ b/defaults/up.sh @@ -0,0 +1,332 @@ +#!/usr/bin/env bash + +# 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 +# +# http://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. + +script_path="${0}" + +# The absolute path to the directory which this script is in. +start_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +run_info_file="${start_dir}/run.info" + +# The absolute path to the root Kafka directory +kafka_dir="$( cd "${start_dir}/../kafka" && pwd )" + +data_path="/data/kafka" + +# Exit with an error message. +die() { + echo "$@" + exit 1 +} + +echo_and_do() { + local cmd="${@}" + echo "${cmd}" + ${cmd} +} + +# Run a command and die if it fails. +# +# Optional flags: +# -v: print the command before running it. +# -o: display the command output. +# $@: The command to run. +must_do() { + local verbose=0 + local output="/dev/null" + while true; do + case ${1} in + -v) + verbose=1 + shift + ;; + -o) + output="/dev/stdout" + shift + ;; + *) break ;; + esac + done + local cmd="$*" + [[ "${verbose}" -eq 1 ]] && echo "${cmd}" + eval "${cmd}" >${output} || die "${1} failed" +} + +# Display a usage message on the terminal and exit. +# +# $1: The exit status to use +usage() { + local exit_status="${1}" + cat </dev/null || die "You must install ${cmd} to run this script." + done +} + +# Set a global variable to a value. +# +# $1: The variable name to set. This function will die if the variable already has a value. The +# variable will be made readonly to prevent any future modifications. +# $2: The value to set the variable to. This function will die if the value is empty or starts +# with a dash. +# $3: A human-readable description of the variable. +set_once() { + local key="${1}" + local value="${2}" + local what="${3}" + [[ -n "${!key}" ]] && die "Error: more than one value specified for ${what}." + verify_command_line_argument "${value}" "${what}" + # It would be better to use declare -g, but older bash versions don't support it. + export "${key}"="${value}" +} + +# Verify that a command-line argument is present and does not start with a slash. +# +# $1: The command-line argument to verify. +# $2: A human-readable description of the variable. +verify_command_line_argument() { + local value="${1}" + local what="${2}" + [[ -n "${value}" ]] || die "Error: no value specified for ${what}" + [[ ${value} == -* ]] && die "Error: invalid value ${value} specified for ${what}" +} + +setup_value() { + key=$1 + value=$2 + file=$3 + # replace special characters + value=${value//&/\\&} + value=${value//#//\\#/} + echo "setup_value: key=${key}, value=${value}, file=${file}" + sed -i "s|^${key}=.*$|${key}=${value}|" "${file}" +} + +add_or_setup_value() { + key=$1 + value=$2 + file=$3 + if grep -q "^${key}" "${file}"; then + setup_value "${key}" "${value}" "${file}" + else + echo "${key}=${value}" | tee -a "${file}" >/dev/null + fi +} + +auto_balancer_setting_for_all() { + file_name=$1 + add_or_setup_value "autobalancer.topic" "AutoBalancerMetricsReporterTopic" "${file_name}" + add_or_setup_value "autobalancer.topic.num.partitions" "1" "${file_name}" +} + +auto_balancer_setting_for_controller_only() { + file_name=$1 + add_or_setup_value "autobalancer.controller.enable" "true" "${file_name}" + add_or_setup_value "autobalancer.controller.exclude.topics" "__consumer_offsets" "${file_name}" +} + +auto_balancer_setting_for_broker_only() { + file_name=$1 + add_or_setup_value "metric.reporters" "kafka.autobalancer.metricsreporter.AutoBalancerMetricsReporter" "${file_name}" +} + +turn_on_auto_balancer() { + role=$1 + file_name=$2 + auto_balancer_setting_for_all "${file_name}" + if [[ "${role}" == "broker" ]]; then + auto_balancer_setting_for_broker_only "${file_name}" + elif [[ "${role}" == "controller" ]]; then + auto_balancer_setting_for_controller_only "${file_name}" + elif [[ "${role}" == "server" ]]; then + auto_balancer_setting_for_controller_only "${file_name}" + auto_balancer_setting_for_broker_only "${file_name}" + fi +} + + +# monitor and change advertised ip for kafka +kafka_monitor_ip() { + process_role=$(grep "role" "${run_info_file}" | awk -F= '{print $2}') + [[ -n "${process_role}" ]] || die "kafka_down: failed to get node role" + + # get private ip first + local_private_ip=$(hostname -I | awk '{print $1}') + if [[ "x${local_private_ip}" == "x" || "x${local_private_ip}" == "x127.0.0.1" ]]; then + die "kafka_start_up: failed to find the local private IP address." + fi + advertised_ip="${local_private_ip}" + + # change ip settings for this node + if [[ "${process_role}" == "server" ]]; then + setup_value "listeners" "PLAINTEXT://${local_private_ip}:9092,CONTROLLER://${local_private_ip}:9093" "${kafka_dir}/config/kraft/${process_role}.properties" + setup_value "advertised.listeners" "PLAINTEXT://${advertised_ip}:9092" "${kafka_dir}/config/kraft/${process_role}.properties" + elif [[ "${process_role}" == "broker" ]]; then + setup_value "listeners" "PLAINTEXT://${local_private_ip}:9092" "${kafka_dir}/config/kraft/${process_role}.properties" + setup_value "advertised.listeners" "PLAINTEXT://${advertised_ip}:9092" "${kafka_dir}/config/kraft/${process_role}.properties" + elif [[ "${process_role}" == "controller" ]]; then + setup_value "listeners" "CONTROLLER://${local_private_ip}:9093" "${kafka_dir}/config/kraft/${process_role}.properties" + else + die "kafka_monitor_ip: unknown process role ${process_role}" + fi +} + +configure_from_environment_variables() { + file_name=$1 + # List of special cases to apply to the variables + local -r exception_regexps=( + "s/sasl\.ssl/sasl_ssl/g" + "s/sasl\.plaintext/sasl_plaintext/g" + ) + # Map environment variables to config properties + for var in "${!KAFKA_CFG_@}"; do + key="$(echo "$var" | sed -e 's/^KAFKA_CFG_//g' -e 's/_/\./g' | tr '[:upper:]' '[:lower:]')" + + # Exception for the camel case in this environment variable + [[ "$var" == "KAFKA_CFG_ZOOKEEPER_CLIENTCNXNSOCKET" ]] && key="zookeeper.clientCnxnSocket" + + # Apply exception regexps + for regex in "${exception_regexps[@]}"; do + key="$(echo "$key" | sed "$regex")" + done + + value="${!var}" + add_or_setup_value "${key}" "${value}" "${file_name}" + done +} + +kafka_up() { + echo "kafka_up: start" + + while [[ $# -ge 1 ]]; do + case "${1}" in + --process.roles) set_once process_role "${2}" "role of this node"; shift 2;; + --node.id) set_once node_id "${2}" "id of this node"; shift 2;; + --controller.quorum.voters) set_once quorum_voters "${2}" "controller quorum voters"; shift 2;; + --s3.region) set_once s3_region "${2}" "regions of s3"; shift 2;; + --s3.bucket) set_once s3_bucket "${2}" "bucket name of s3"; shift 2;; + --cluster.id) set_once cluster_id "${2}" "kafka cluster id"; shift 2;; + --s3.access.key) set_once s3_access_key "${2}" "s3 access key"; shift 2;; + --s3.secret.key) set_once s3_secret_key "${2}" "s3 secret key"; shift 2;; + --s3.endpoint) set_once s3_endpoint "${2}" "s3 endpoint"; shift 2;; + esac + done + + pid=$(jcmd | grep -e kafka.Kafka | awk '{print $1}') + if [[ -n "${pid}" ]]; then + echo "kafka_up: kafka is already running, pid=${pid}" + exit 0 + fi + + [[ -n "${node_id}" ]] || die "node_id is empty" + [[ -n "${process_role}" ]] || die "process_role is empty" + [[ -n "${quorum_voters}" ]] || die "quorum_voters is empty" + [[ -n "${s3_region}" ]] || s3_region="${AWS_DEFAULT_REGION}" + [[ -n "${s3_bucket}" ]] || die "s3_bucket is empty" + [[ -n "${s3_access_key}" ]] || s3_access_key="${KAFKA_S3_ACCESS_KEY}" + [[ -n "${s3_secret_key}" ]] || s3_secret_key="${KAFKA_S3_SECRET_KEY}" + [[ -n "${s3_endpoint}" ]] || die "s3_endpoint is empty" + [[ -n "${cluster_id}" ]] || cluster_id="rZdE0DjZSrqy96PXrMUZVw" + + for role in "broker" "controller" "server"; do + setup_value "node.id" "${node_id}" "${kafka_dir}/config/kraft/${role}.properties" + setup_value "controller.quorum.voters" "${quorum_voters}" "${kafka_dir}/config/kraft/${role}.properties" + setup_value "s3.data.bucket" "0@s3://${s3_bucket}?region=${s3_region}&endpoint=${s3_endpoint}&accessKey=static" "${kafka_dir}/config/kraft/${role}.properties" + setup_value "s3.ops.bucket" "0@s3://${s3_bucket}?region=${s3_region}&endpoint=${s3_endpoint}&accessKey=static" "${kafka_dir}/config/kraft/${role}.properties" + setup_value "log.dirs" "${data_path}/kraft-${role}-logs" "${kafka_dir}/config/kraft/${role}.properties" + setup_value "s3.wal.path" "0@file://${data_path}/wal?capacity=2147483648" "${kafka_dir}/config/kraft/${role}.properties" + # turn on auto_balancer + turn_on_auto_balancer "${role}" "${kafka_dir}/config/kraft/${role}.properties" + done + + if [[ -n "${KAFKA_HEAP_OPTS}" ]]; then + kafka_heap_opts="${KAFKA_HEAP_OPTS}" + elif [[ "${process_role}" == "broker" || "${process_role}" == "server" ]]; then + kafka_heap_opts="-Xms1g -Xmx1g -XX:MetaspaceSize=96m -XX:MaxDirectMemorySize=1G" + elif [[ "${process_role}" == "controller" ]]; then + kafka_heap_opts="-Xms1g -Xmx1g -XX:MetaspaceSize=96m" + else + die "kafka_start_up: unknown process role ${process_role}" + fi + + # add this node's info to run.info + setup_value "node.id" "${node_id}" "${run_info_file}" + setup_value "role" "${process_role}" "${run_info_file}" + setup_value "kafka.base.path" "${kafka_dir}" "${run_info_file}" + setup_value "kafka.data.path" "${data_path}" "${run_info_file}" + + # change ip settings here + kafka_monitor_ip + echo "kafka_up: ip settings changed" + + # override settings from env + configure_from_environment_variables "${kafka_dir}/config/kraft/${process_role}.properties" + + # Disable the default console logger in favour of KafkaAppender (which provides the exact output) + echo "log4j.appender.stdout.Threshold=OFF" >> "${kafka_dir}/config/log4j.properties" + + # format the data path + must_do -v "${kafka_dir}/bin/kafka-storage.sh format -g -t ${cluster_id} -c ${kafka_dir}/config/kraft/${process_role}.properties" + + exec "${kafka_dir}/bin/kafka-server-start.sh" "${kafka_dir}/config/kraft/${process_role}.properties" +} + +# Parse command-line arguments +[[ $# -lt 1 ]] && usage 0 +# Display the help text if -h or --help appears in the command line +for arg in "${@}"; do + case "${arg}" in + -h | --help) usage 0 ;; + --) break ;; + *) ;; + esac +done +action="${1}" +shift +case "${action}" in +help) usage 0 ;; + +up) + kafka_"${action}" "${@}" + exit 0 + ;; + +*) + echo "Unknown command '${action}'. Type '${script_path} --help' for usage information." + exit 1 + ;; +esac diff --git a/defaults/zz_generated_bindata.go b/defaults/zz_generated_bindata.go new file mode 100644 index 0000000..1591b4d --- /dev/null +++ b/defaults/zz_generated_bindata.go @@ -0,0 +1,236 @@ +// Code generated for package defaults by go-bindata DO NOT EDIT. (@generated) +// sources: +// defaults/up.sh +package defaults + +import ( + "fmt" + "io/ioutil" + "os" + "path/filepath" + "reflect" + "strings" + "time" + "unsafe" +) + +func bindataRead(data, name string) ([]byte, error) { + var empty [0]byte + sx := (*reflect.StringHeader)(unsafe.Pointer(&data)) + b := empty[:] + bx := (*reflect.SliceHeader)(unsafe.Pointer(&b)) + bx.Data = sx.Data + bx.Len = len(data) + bx.Cap = bx.Len + return b, nil +} + +type asset struct { + bytes []byte + info os.FileInfo +} + +type bindataFileInfo struct { + name string + size int64 + mode os.FileMode + modTime time.Time +} + +// Name return file name +func (fi bindataFileInfo) Name() string { + return fi.name +} + +// Size return file size +func (fi bindataFileInfo) Size() int64 { + return fi.size +} + +// Mode return file mode +func (fi bindataFileInfo) Mode() os.FileMode { + return fi.mode +} + +// Mode return file modify time +func (fi bindataFileInfo) ModTime() time.Time { + return fi.modTime +} + +// IsDir return file whether a directory +func (fi bindataFileInfo) IsDir() bool { + return fi.mode&os.ModeDir != 0 +} + +// Sys return file is sys mode +func (fi bindataFileInfo) Sys() interface{} { + return nil +} + +var _defaultsUpSh = "\x23\x21\x2f\x75\x73\x72\x2f\x62\x69\x6e\x2f\x65\x6e\x76\x20\x62\x61\x73\x68\x0a\x0a\x23\x20\x4c\x69\x63\x65\x6e\x73\x65\x64\x20\x74\x6f\x20\x74\x68\x65\x20\x41\x70\x61\x63\x68\x65\x20\x53\x6f\x66\x74\x77\x61\x72\x65\x20\x46\x6f\x75\x6e\x64\x61\x74\x69\x6f\x6e\x20\x28\x41\x53\x46\x29\x20\x75\x6e\x64\x65\x72\x20\x6f\x6e\x65\x20\x6f\x72\x20\x6d\x6f\x72\x65\x0a\x23\x20\x63\x6f\x6e\x74\x72\x69\x62\x75\x74\x6f\x72\x20\x6c\x69\x63\x65\x6e\x73\x65\x20\x61\x67\x72\x65\x65\x6d\x65\x6e\x74\x73\x2e\x20\x20\x53\x65\x65\x20\x74\x68\x65\x20\x4e\x4f\x54\x49\x43\x45\x20\x66\x69\x6c\x65\x20\x64\x69\x73\x74\x72\x69\x62\x75\x74\x65\x64\x20\x77\x69\x74\x68\x0a\x23\x20\x74\x68\x69\x73\x20\x77\x6f\x72\x6b\x20\x66\x6f\x72\x20\x61\x64\x64\x69\x74\x69\x6f\x6e\x61\x6c\x20\x69\x6e\x66\x6f\x72\x6d\x61\x74\x69\x6f\x6e\x20\x72\x65\x67\x61\x72\x64\x69\x6e\x67\x20\x63\x6f\x70\x79\x72\x69\x67\x68\x74\x20\x6f\x77\x6e\x65\x72\x73\x68\x69\x70\x2e\x0a\x23\x20\x54\x68\x65\x20\x41\x53\x46\x20\x6c\x69\x63\x65\x6e\x73\x65\x73\x20\x74\x68\x69\x73\x20\x66\x69\x6c\x65\x20\x74\x6f\x20\x59\x6f\x75\x20\x75\x6e\x64\x65\x72\x20\x74\x68\x65\x20\x41\x70\x61\x63\x68\x65\x20\x4c\x69\x63\x65\x6e\x73\x65\x2c\x20\x56\x65\x72\x73\x69\x6f\x6e\x20\x32\x2e\x30\x0a\x23\x20\x28\x74\x68\x65\x20\x22\x4c\x69\x63\x65\x6e\x73\x65\x22\x29\x3b\x20\x79\x6f\x75\x20\x6d\x61\x79\x20\x6e\x6f\x74\x20\x75\x73\x65\x20\x74\x68\x69\x73\x20\x66\x69\x6c\x65\x20\x65\x78\x63\x65\x70\x74\x20\x69\x6e\x20\x63\x6f\x6d\x70\x6c\x69\x61\x6e\x63\x65\x20\x77\x69\x74\x68\x0a\x23\x20\x74\x68\x65\x20\x4c\x69\x63\x65\x6e\x73\x65\x2e\x20\x20\x59\x6f\x75\x20\x6d\x61\x79\x20\x6f\x62\x74\x61\x69\x6e\x20\x61\x20\x63\x6f\x70\x79\x20\x6f\x66\x20\x74\x68\x65\x20\x4c\x69\x63\x65\x6e\x73\x65\x20\x61\x74\x0a\x23\x0a\x23\x20\x20\x20\x20\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x61\x70\x61\x63\x68\x65\x2e\x6f\x72\x67\x2f\x6c\x69\x63\x65\x6e\x73\x65\x73\x2f\x4c\x49\x43\x45\x4e\x53\x45\x2d\x32\x2e\x30\x0a\x23\x0a\x23\x20\x55\x6e\x6c\x65\x73\x73\x20\x72\x65\x71\x75\x69\x72\x65\x64\x20\x62\x79\x20\x61\x70\x70\x6c\x69\x63\x61\x62\x6c\x65\x20\x6c\x61\x77\x20\x6f\x72\x20\x61\x67\x72\x65\x65\x64\x20\x74\x6f\x20\x69\x6e\x20\x77\x72\x69\x74\x69\x6e\x67\x2c\x20\x73\x6f\x66\x74\x77\x61\x72\x65\x0a\x23\x20\x64\x69\x73\x74\x72\x69\x62\x75\x74\x65\x64\x20\x75\x6e\x64\x65\x72\x20\x74\x68\x65\x20\x4c\x69\x63\x65\x6e\x73\x65\x20\x69\x73\x20\x64\x69\x73\x74\x72\x69\x62\x75\x74\x65\x64\x20\x6f\x6e\x20\x61\x6e\x20\x22\x41\x53\x20\x49\x53\x22\x20\x42\x41\x53\x49\x53\x2c\x0a\x23\x20\x57\x49\x54\x48\x4f\x55\x54\x20\x57\x41\x52\x52\x41\x4e\x54\x49\x45\x53\x20\x4f\x52\x20\x43\x4f\x4e\x44\x49\x54\x49\x4f\x4e\x53\x20\x4f\x46\x20\x41\x4e\x59\x20\x4b\x49\x4e\x44\x2c\x20\x65\x69\x74\x68\x65\x72\x20\x65\x78\x70\x72\x65\x73\x73\x20\x6f\x72\x20\x69\x6d\x70\x6c\x69\x65\x64\x2e\x0a\x23\x20\x53\x65\x65\x20\x74\x68\x65\x20\x4c\x69\x63\x65\x6e\x73\x65\x20\x66\x6f\x72\x20\x74\x68\x65\x20\x73\x70\x65\x63\x69\x66\x69\x63\x20\x6c\x61\x6e\x67\x75\x61\x67\x65\x20\x67\x6f\x76\x65\x72\x6e\x69\x6e\x67\x20\x70\x65\x72\x6d\x69\x73\x73\x69\x6f\x6e\x73\x20\x61\x6e\x64\x0a\x23\x20\x6c\x69\x6d\x69\x74\x61\x74\x69\x6f\x6e\x73\x20\x75\x6e\x64\x65\x72\x20\x74\x68\x65\x20\x4c\x69\x63\x65\x6e\x73\x65\x2e\x0a\x0a\x73\x63\x72\x69\x70\x74\x5f\x70\x61\x74\x68\x3d\x22\x24\x7b\x30\x7d\x22\x0a\x0a\x23\x20\x54\x68\x65\x20\x61\x62\x73\x6f\x6c\x75\x74\x65\x20\x70\x61\x74\x68\x20\x74\x6f\x20\x74\x68\x65\x20\x64\x69\x72\x65\x63\x74\x6f\x72\x79\x20\x77\x68\x69\x63\x68\x20\x74\x68\x69\x73\x20\x73\x63\x72\x69\x70\x74\x20\x69\x73\x20\x69\x6e\x2e\x0a\x73\x74\x61\x72\x74\x5f\x64\x69\x72\x3d\x22\x24\x28\x63\x64\x20\x22\x24\x28\x64\x69\x72\x6e\x61\x6d\x65\x20\x22\x24\x7b\x42\x41\x53\x48\x5f\x53\x4f\x55\x52\x43\x45\x5b\x30\x5d\x7d\x22\x29\x22\x20\x26\x26\x20\x70\x77\x64\x29\x22\x0a\x0a\x72\x75\x6e\x5f\x69\x6e\x66\x6f\x5f\x66\x69\x6c\x65\x3d\x22\x24\x7b\x73\x74\x61\x72\x74\x5f\x64\x69\x72\x7d\x2f\x72\x75\x6e\x2e\x69\x6e\x66\x6f\x22\x0a\x0a\x23\x20\x54\x68\x65\x20\x61\x62\x73\x6f\x6c\x75\x74\x65\x20\x70\x61\x74\x68\x20\x74\x6f\x20\x74\x68\x65\x20\x72\x6f\x6f\x74\x20\x4b\x61\x66\x6b\x61\x20\x64\x69\x72\x65\x63\x74\x6f\x72\x79\x0a\x6b\x61\x66\x6b\x61\x5f\x64\x69\x72\x3d\x22\x24\x28\x20\x63\x64\x20\x22\x24\x7b\x73\x74\x61\x72\x74\x5f\x64\x69\x72\x7d\x2f\x2e\x2e\x2f\x6b\x61\x66\x6b\x61\x22\x20\x26\x26\x20\x70\x77\x64\x20\x29\x22\x0a\x0a\x64\x61\x74\x61\x5f\x70\x61\x74\x68\x3d\x22\x2f\x64\x61\x74\x61\x2f\x6b\x61\x66\x6b\x61\x22\x0a\x0a\x23\x20\x45\x78\x69\x74\x20\x77\x69\x74\x68\x20\x61\x6e\x20\x65\x72\x72\x6f\x72\x20\x6d\x65\x73\x73\x61\x67\x65\x2e\x0a\x64\x69\x65\x28\x29\x20\x7b\x0a\x20\x20\x65\x63\x68\x6f\x20\x22\x24\x40\x22\x0a\x20\x20\x65\x78\x69\x74\x20\x31\x0a\x7d\x0a\x0a\x65\x63\x68\x6f\x5f\x61\x6e\x64\x5f\x64\x6f\x28\x29\x20\x7b\x0a\x20\x20\x20\x20\x6c\x6f\x63\x61\x6c\x20\x63\x6d\x64\x3d\x22\x24\x7b\x40\x7d\x22\x0a\x20\x20\x20\x20\x65\x63\x68\x6f\x20\x22\x24\x7b\x63\x6d\x64\x7d\x22\x0a\x20\x20\x20\x20\x24\x7b\x63\x6d\x64\x7d\x0a\x7d\x0a\x0a\x23\x20\x52\x75\x6e\x20\x61\x20\x63\x6f\x6d\x6d\x61\x6e\x64\x20\x61\x6e\x64\x20\x64\x69\x65\x20\x69\x66\x20\x69\x74\x20\x66\x61\x69\x6c\x73\x2e\x0a\x23\x0a\x23\x20\x4f\x70\x74\x69\x6f\x6e\x61\x6c\x20\x66\x6c\x61\x67\x73\x3a\x0a\x23\x20\x2d\x76\x3a\x20\x70\x72\x69\x6e\x74\x20\x74\x68\x65\x20\x63\x6f\x6d\x6d\x61\x6e\x64\x20\x62\x65\x66\x6f\x72\x65\x20\x72\x75\x6e\x6e\x69\x6e\x67\x20\x69\x74\x2e\x0a\x23\x20\x2d\x6f\x3a\x20\x64\x69\x73\x70\x6c\x61\x79\x20\x74\x68\x65\x20\x63\x6f\x6d\x6d\x61\x6e\x64\x20\x6f\x75\x74\x70\x75\x74\x2e\x0a\x23\x20\x24\x40\x3a\x20\x54\x68\x65\x20\x63\x6f\x6d\x6d\x61\x6e\x64\x20\x74\x6f\x20\x72\x75\x6e\x2e\x0a\x6d\x75\x73\x74\x5f\x64\x6f\x28\x29\x20\x7b\x0a\x20\x20\x6c\x6f\x63\x61\x6c\x20\x76\x65\x72\x62\x6f\x73\x65\x3d\x30\x0a\x20\x20\x6c\x6f\x63\x61\x6c\x20\x6f\x75\x74\x70\x75\x74\x3d\x22\x2f\x64\x65\x76\x2f\x6e\x75\x6c\x6c\x22\x0a\x20\x20\x77\x68\x69\x6c\x65\x20\x74\x72\x75\x65\x3b\x20\x64\x6f\x0a\x20\x20\x20\x20\x63\x61\x73\x65\x20\x24\x7b\x31\x7d\x20\x69\x6e\x0a\x20\x20\x20\x20\x2d\x76\x29\x0a\x20\x20\x20\x20\x20\x20\x76\x65\x72\x62\x6f\x73\x65\x3d\x31\x0a\x20\x20\x20\x20\x20\x20\x73\x68\x69\x66\x74\x0a\x20\x20\x20\x20\x20\x20\x3b\x3b\x0a\x20\x20\x20\x20\x2d\x6f\x29\x0a\x20\x20\x20\x20\x20\x20\x6f\x75\x74\x70\x75\x74\x3d\x22\x2f\x64\x65\x76\x2f\x73\x74\x64\x6f\x75\x74\x22\x0a\x20\x20\x20\x20\x20\x20\x73\x68\x69\x66\x74\x0a\x20\x20\x20\x20\x20\x20\x3b\x3b\x0a\x20\x20\x20\x20\x2a\x29\x20\x62\x72\x65\x61\x6b\x20\x3b\x3b\x0a\x20\x20\x20\x20\x65\x73\x61\x63\x0a\x20\x20\x64\x6f\x6e\x65\x0a\x20\x20\x6c\x6f\x63\x61\x6c\x20\x63\x6d\x64\x3d\x22\x24\x2a\x22\x0a\x20\x20\x5b\x5b\x20\x22\x24\x7b\x76\x65\x72\x62\x6f\x73\x65\x7d\x22\x20\x2d\x65\x71\x20\x31\x20\x5d\x5d\x20\x26\x26\x20\x65\x63\x68\x6f\x20\x22\x24\x7b\x63\x6d\x64\x7d\x22\x0a\x20\x20\x65\x76\x61\x6c\x20\x22\x24\x7b\x63\x6d\x64\x7d\x22\x20\x3e\x24\x7b\x6f\x75\x74\x70\x75\x74\x7d\x20\x7c\x7c\x20\x64\x69\x65\x20\x22\x24\x7b\x31\x7d\x20\x66\x61\x69\x6c\x65\x64\x22\x0a\x7d\x0a\x0a\x23\x20\x44\x69\x73\x70\x6c\x61\x79\x20\x61\x20\x75\x73\x61\x67\x65\x20\x6d\x65\x73\x73\x61\x67\x65\x20\x6f\x6e\x20\x74\x68\x65\x20\x74\x65\x72\x6d\x69\x6e\x61\x6c\x20\x61\x6e\x64\x20\x65\x78\x69\x74\x2e\x0a\x23\x0a\x23\x20\x24\x31\x3a\x20\x54\x68\x65\x20\x65\x78\x69\x74\x20\x73\x74\x61\x74\x75\x73\x20\x74\x6f\x20\x75\x73\x65\x0a\x75\x73\x61\x67\x65\x28\x29\x20\x7b\x0a\x20\x20\x6c\x6f\x63\x61\x6c\x20\x65\x78\x69\x74\x5f\x73\x74\x61\x74\x75\x73\x3d\x22\x24\x7b\x31\x7d\x22\x0a\x20\x20\x63\x61\x74\x20\x3c\x3c\x45\x4f\x46\x0a\x73\x74\x61\x72\x74\x3a\x20\x61\x20\x74\x6f\x6f\x6c\x20\x66\x6f\x72\x20\x73\x74\x61\x72\x74\x69\x6e\x67\x20\x27\x41\x75\x74\x6f\x4d\x51\x20\x66\x6f\x72\x20\x41\x70\x61\x63\x68\x65\x20\x4b\x61\x66\x6b\x61\x20\x6f\x6e\x20\x53\x33\x27\x2e\x0a\x0a\x55\x73\x61\x67\x65\x3a\x20\x24\x7b\x73\x63\x72\x69\x70\x74\x5f\x70\x61\x74\x68\x7d\x20\x5b\x63\x6f\x6d\x6d\x61\x6e\x64\x5d\x20\x5b\x6f\x70\x74\x69\x6f\x6e\x73\x5d\x0a\x0a\x68\x65\x6c\x70\x7c\x2d\x68\x7c\x2d\x2d\x68\x65\x6c\x70\x0a\x20\x20\x20\x20\x44\x69\x73\x70\x6c\x61\x79\x20\x74\x68\x69\x73\x20\x68\x65\x6c\x70\x20\x6d\x65\x73\x73\x61\x67\x65\x0a\x75\x70\x20\x5b\x2d\x2d\x70\x72\x6f\x63\x65\x73\x73\x2e\x72\x6f\x6c\x65\x73\x20\x52\x4f\x4c\x45\x5d\x20\x5b\x2d\x2d\x6e\x6f\x64\x65\x2e\x69\x64\x20\x4e\x4f\x44\x45\x5f\x49\x44\x5d\x20\x5b\x2d\x2d\x63\x6f\x6e\x74\x72\x6f\x6c\x6c\x65\x72\x2e\x71\x75\x6f\x72\x75\x6d\x2e\x76\x6f\x74\x65\x72\x73\x20\x56\x4f\x54\x45\x52\x53\x5d\x0a\x20\x20\x20\x5b\x2d\x2d\x73\x33\x2e\x72\x65\x67\x69\x6f\x6e\x20\x52\x45\x47\x49\x4f\x4e\x5d\x20\x5b\x2d\x2d\x73\x33\x2e\x62\x75\x63\x6b\x65\x74\x20\x42\x55\x43\x4b\x45\x54\x5d\x20\x5b\x2d\x2d\x73\x33\x2e\x65\x6e\x64\x70\x6f\x69\x6e\x74\x20\x45\x4e\x44\x50\x4f\x49\x4e\x54\x5d\x0a\x20\x20\x20\x5b\x2d\x2d\x73\x33\x2e\x61\x63\x63\x65\x73\x73\x2e\x6b\x65\x79\x20\x41\x43\x43\x45\x53\x53\x5f\x4b\x45\x59\x5d\x20\x5b\x2d\x2d\x73\x33\x2e\x73\x65\x63\x72\x65\x74\x2e\x6b\x65\x79\x20\x53\x45\x43\x52\x45\x54\x5f\x4b\x45\x59\x5d\x0a\x20\x20\x20\x20\x73\x74\x61\x72\x74\x20\x6e\x6f\x64\x65\x2e\x0a\x45\x4f\x46\x0a\x20\x20\x65\x78\x69\x74\x20\x22\x24\x7b\x65\x78\x69\x74\x5f\x73\x74\x61\x74\x75\x73\x7d\x22\x0a\x7d\x0a\x0a\x23\x20\x43\x68\x65\x63\x6b\x20\x66\x6f\x72\x20\x74\x68\x65\x20\x70\x72\x65\x73\x65\x6e\x63\x65\x20\x6f\x66\x20\x63\x65\x72\x74\x61\x69\x6e\x20\x63\x6f\x6d\x6d\x61\x6e\x64\x73\x2e\x0a\x23\x0a\x23\x20\x24\x40\x3a\x20\x54\x68\x65\x20\x63\x6f\x6d\x6d\x61\x6e\x64\x73\x20\x74\x6f\x20\x63\x68\x65\x63\x6b\x20\x66\x6f\x72\x2e\x20\x20\x54\x68\x69\x73\x20\x66\x75\x6e\x63\x74\x69\x6f\x6e\x20\x77\x69\x6c\x6c\x20\x64\x69\x65\x20\x69\x66\x20\x61\x6e\x79\x20\x6f\x66\x20\x74\x68\x65\x73\x65\x20\x63\x6f\x6d\x6d\x61\x6e\x64\x73\x20\x61\x72\x65\x20\x6e\x6f\x74\x20\x66\x6f\x75\x6e\x64\x20\x62\x79\x0a\x23\x20\x20\x20\x20\x20\x20\x20\x74\x68\x65\x20\x27\x77\x68\x69\x63\x68\x27\x20\x63\x6f\x6d\x6d\x61\x6e\x64\x2e\x0a\x72\x65\x71\x75\x69\x72\x65\x5f\x63\x6f\x6d\x6d\x61\x6e\x64\x73\x28\x29\x20\x7b\x0a\x20\x20\x6c\x6f\x63\x61\x6c\x20\x63\x6d\x64\x73\x3d\x28\x22\x24\x40\x22\x29\x0a\x20\x20\x66\x6f\x72\x20\x63\x6d\x64\x20\x69\x6e\x20\x22\x24\x7b\x63\x6d\x64\x73\x5b\x40\x5d\x7d\x22\x3b\x20\x64\x6f\x0a\x20\x20\x20\x20\x77\x68\x69\x63\x68\x20\x2d\x2d\x20\x22\x24\x7b\x63\x6d\x64\x7d\x22\x20\x26\x3e\x2f\x64\x65\x76\x2f\x6e\x75\x6c\x6c\x20\x7c\x7c\x20\x64\x69\x65\x20\x22\x59\x6f\x75\x20\x6d\x75\x73\x74\x20\x69\x6e\x73\x74\x61\x6c\x6c\x20\x24\x7b\x63\x6d\x64\x7d\x20\x74\x6f\x20\x72\x75\x6e\x20\x74\x68\x69\x73\x20\x73\x63\x72\x69\x70\x74\x2e\x22\x0a\x20\x20\x64\x6f\x6e\x65\x0a\x7d\x0a\x0a\x23\x20\x53\x65\x74\x20\x61\x20\x67\x6c\x6f\x62\x61\x6c\x20\x76\x61\x72\x69\x61\x62\x6c\x65\x20\x74\x6f\x20\x61\x20\x76\x61\x6c\x75\x65\x2e\x0a\x23\x0a\x23\x20\x24\x31\x3a\x20\x54\x68\x65\x20\x76\x61\x72\x69\x61\x62\x6c\x65\x20\x6e\x61\x6d\x65\x20\x74\x6f\x20\x73\x65\x74\x2e\x20\x20\x54\x68\x69\x73\x20\x66\x75\x6e\x63\x74\x69\x6f\x6e\x20\x77\x69\x6c\x6c\x20\x64\x69\x65\x20\x69\x66\x20\x74\x68\x65\x20\x76\x61\x72\x69\x61\x62\x6c\x65\x20\x61\x6c\x72\x65\x61\x64\x79\x20\x68\x61\x73\x20\x61\x20\x76\x61\x6c\x75\x65\x2e\x20\x20\x54\x68\x65\x0a\x23\x20\x20\x20\x20\x20\x76\x61\x72\x69\x61\x62\x6c\x65\x20\x77\x69\x6c\x6c\x20\x62\x65\x20\x6d\x61\x64\x65\x20\x72\x65\x61\x64\x6f\x6e\x6c\x79\x20\x74\x6f\x20\x70\x72\x65\x76\x65\x6e\x74\x20\x61\x6e\x79\x20\x66\x75\x74\x75\x72\x65\x20\x6d\x6f\x64\x69\x66\x69\x63\x61\x74\x69\x6f\x6e\x73\x2e\x0a\x23\x20\x24\x32\x3a\x20\x54\x68\x65\x20\x76\x61\x6c\x75\x65\x20\x74\x6f\x20\x73\x65\x74\x20\x74\x68\x65\x20\x76\x61\x72\x69\x61\x62\x6c\x65\x20\x74\x6f\x2e\x20\x20\x54\x68\x69\x73\x20\x66\x75\x6e\x63\x74\x69\x6f\x6e\x20\x77\x69\x6c\x6c\x20\x64\x69\x65\x20\x69\x66\x20\x74\x68\x65\x20\x76\x61\x6c\x75\x65\x20\x69\x73\x20\x65\x6d\x70\x74\x79\x20\x6f\x72\x20\x73\x74\x61\x72\x74\x73\x0a\x23\x20\x20\x20\x20\x20\x77\x69\x74\x68\x20\x61\x20\x64\x61\x73\x68\x2e\x0a\x23\x20\x24\x33\x3a\x20\x41\x20\x68\x75\x6d\x61\x6e\x2d\x72\x65\x61\x64\x61\x62\x6c\x65\x20\x64\x65\x73\x63\x72\x69\x70\x74\x69\x6f\x6e\x20\x6f\x66\x20\x74\x68\x65\x20\x76\x61\x72\x69\x61\x62\x6c\x65\x2e\x0a\x73\x65\x74\x5f\x6f\x6e\x63\x65\x28\x29\x20\x7b\x0a\x20\x20\x20\x20\x6c\x6f\x63\x61\x6c\x20\x6b\x65\x79\x3d\x22\x24\x7b\x31\x7d\x22\x0a\x20\x20\x20\x20\x6c\x6f\x63\x61\x6c\x20\x76\x61\x6c\x75\x65\x3d\x22\x24\x7b\x32\x7d\x22\x0a\x20\x20\x20\x20\x6c\x6f\x63\x61\x6c\x20\x77\x68\x61\x74\x3d\x22\x24\x7b\x33\x7d\x22\x0a\x20\x20\x20\x20\x5b\x5b\x20\x2d\x6e\x20\x22\x24\x7b\x21\x6b\x65\x79\x7d\x22\x20\x5d\x5d\x20\x26\x26\x20\x64\x69\x65\x20\x22\x45\x72\x72\x6f\x72\x3a\x20\x6d\x6f\x72\x65\x20\x74\x68\x61\x6e\x20\x6f\x6e\x65\x20\x76\x61\x6c\x75\x65\x20\x73\x70\x65\x63\x69\x66\x69\x65\x64\x20\x66\x6f\x72\x20\x24\x7b\x77\x68\x61\x74\x7d\x2e\x22\x0a\x20\x20\x20\x20\x76\x65\x72\x69\x66\x79\x5f\x63\x6f\x6d\x6d\x61\x6e\x64\x5f\x6c\x69\x6e\x65\x5f\x61\x72\x67\x75\x6d\x65\x6e\x74\x20\x22\x24\x7b\x76\x61\x6c\x75\x65\x7d\x22\x20\x22\x24\x7b\x77\x68\x61\x74\x7d\x22\x0a\x20\x20\x20\x20\x23\x20\x49\x74\x20\x77\x6f\x75\x6c\x64\x20\x62\x65\x20\x62\x65\x74\x74\x65\x72\x20\x74\x6f\x20\x75\x73\x65\x20\x64\x65\x63\x6c\x61\x72\x65\x20\x2d\x67\x2c\x20\x62\x75\x74\x20\x6f\x6c\x64\x65\x72\x20\x62\x61\x73\x68\x20\x76\x65\x72\x73\x69\x6f\x6e\x73\x20\x64\x6f\x6e\x27\x74\x20\x73\x75\x70\x70\x6f\x72\x74\x20\x69\x74\x2e\x0a\x20\x20\x20\x20\x65\x78\x70\x6f\x72\x74\x20\x22\x24\x7b\x6b\x65\x79\x7d\x22\x3d\x22\x24\x7b\x76\x61\x6c\x75\x65\x7d\x22\x0a\x7d\x0a\x0a\x23\x20\x56\x65\x72\x69\x66\x79\x20\x74\x68\x61\x74\x20\x61\x20\x63\x6f\x6d\x6d\x61\x6e\x64\x2d\x6c\x69\x6e\x65\x20\x61\x72\x67\x75\x6d\x65\x6e\x74\x20\x69\x73\x20\x70\x72\x65\x73\x65\x6e\x74\x20\x61\x6e\x64\x20\x64\x6f\x65\x73\x20\x6e\x6f\x74\x20\x73\x74\x61\x72\x74\x20\x77\x69\x74\x68\x20\x61\x20\x73\x6c\x61\x73\x68\x2e\x0a\x23\x0a\x23\x20\x24\x31\x3a\x20\x54\x68\x65\x20\x63\x6f\x6d\x6d\x61\x6e\x64\x2d\x6c\x69\x6e\x65\x20\x61\x72\x67\x75\x6d\x65\x6e\x74\x20\x74\x6f\x20\x76\x65\x72\x69\x66\x79\x2e\x0a\x23\x20\x24\x32\x3a\x20\x41\x20\x68\x75\x6d\x61\x6e\x2d\x72\x65\x61\x64\x61\x62\x6c\x65\x20\x64\x65\x73\x63\x72\x69\x70\x74\x69\x6f\x6e\x20\x6f\x66\x20\x74\x68\x65\x20\x76\x61\x72\x69\x61\x62\x6c\x65\x2e\x0a\x76\x65\x72\x69\x66\x79\x5f\x63\x6f\x6d\x6d\x61\x6e\x64\x5f\x6c\x69\x6e\x65\x5f\x61\x72\x67\x75\x6d\x65\x6e\x74\x28\x29\x20\x7b\x0a\x20\x20\x20\x20\x6c\x6f\x63\x61\x6c\x20\x76\x61\x6c\x75\x65\x3d\x22\x24\x7b\x31\x7d\x22\x0a\x20\x20\x20\x20\x6c\x6f\x63\x61\x6c\x20\x77\x68\x61\x74\x3d\x22\x24\x7b\x32\x7d\x22\x0a\x20\x20\x20\x20\x5b\x5b\x20\x2d\x6e\x20\x22\x24\x7b\x76\x61\x6c\x75\x65\x7d\x22\x20\x5d\x5d\x20\x7c\x7c\x20\x64\x69\x65\x20\x22\x45\x72\x72\x6f\x72\x3a\x20\x6e\x6f\x20\x76\x61\x6c\x75\x65\x20\x73\x70\x65\x63\x69\x66\x69\x65\x64\x20\x66\x6f\x72\x20\x24\x7b\x77\x68\x61\x74\x7d\x22\x0a\x20\x20\x20\x20\x5b\x5b\x20\x24\x7b\x76\x61\x6c\x75\x65\x7d\x20\x3d\x3d\x20\x2d\x2a\x20\x5d\x5d\x20\x26\x26\x20\x64\x69\x65\x20\x22\x45\x72\x72\x6f\x72\x3a\x20\x69\x6e\x76\x61\x6c\x69\x64\x20\x76\x61\x6c\x75\x65\x20\x24\x7b\x76\x61\x6c\x75\x65\x7d\x20\x73\x70\x65\x63\x69\x66\x69\x65\x64\x20\x66\x6f\x72\x20\x24\x7b\x77\x68\x61\x74\x7d\x22\x0a\x7d\x0a\x0a\x73\x65\x74\x75\x70\x5f\x76\x61\x6c\x75\x65\x28\x29\x20\x7b\x0a\x20\x20\x6b\x65\x79\x3d\x24\x31\x0a\x20\x20\x76\x61\x6c\x75\x65\x3d\x24\x32\x0a\x20\x20\x66\x69\x6c\x65\x3d\x24\x33\x0a\x20\x20\x23\x20\x72\x65\x70\x6c\x61\x63\x65\x20\x73\x70\x65\x63\x69\x61\x6c\x20\x63\x68\x61\x72\x61\x63\x74\x65\x72\x73\x0a\x20\x20\x76\x61\x6c\x75\x65\x3d\x24\x7b\x76\x61\x6c\x75\x65\x2f\x2f\x26\x2f\x5c\x5c\x26\x7d\x0a\x20\x20\x76\x61\x6c\x75\x65\x3d\x24\x7b\x76\x61\x6c\x75\x65\x2f\x2f\x23\x2f\x2f\x5c\x5c\x23\x2f\x7d\x0a\x20\x20\x65\x63\x68\x6f\x20\x22\x73\x65\x74\x75\x70\x5f\x76\x61\x6c\x75\x65\x3a\x20\x6b\x65\x79\x3d\x24\x7b\x6b\x65\x79\x7d\x2c\x20\x76\x61\x6c\x75\x65\x3d\x24\x7b\x76\x61\x6c\x75\x65\x7d\x2c\x20\x66\x69\x6c\x65\x3d\x24\x7b\x66\x69\x6c\x65\x7d\x22\x0a\x20\x20\x73\x65\x64\x20\x2d\x69\x20\x22\x73\x7c\x5e\x24\x7b\x6b\x65\x79\x7d\x3d\x2e\x2a\x24\x7c\x24\x7b\x6b\x65\x79\x7d\x3d\x24\x7b\x76\x61\x6c\x75\x65\x7d\x7c\x22\x20\x22\x24\x7b\x66\x69\x6c\x65\x7d\x22\x0a\x7d\x0a\x0a\x61\x64\x64\x5f\x6f\x72\x5f\x73\x65\x74\x75\x70\x5f\x76\x61\x6c\x75\x65\x28\x29\x20\x7b\x0a\x20\x20\x6b\x65\x79\x3d\x24\x31\x0a\x20\x20\x76\x61\x6c\x75\x65\x3d\x24\x32\x0a\x20\x20\x66\x69\x6c\x65\x3d\x24\x33\x0a\x20\x20\x69\x66\x20\x67\x72\x65\x70\x20\x2d\x71\x20\x22\x5e\x24\x7b\x6b\x65\x79\x7d\x22\x20\x22\x24\x7b\x66\x69\x6c\x65\x7d\x22\x3b\x20\x74\x68\x65\x6e\x0a\x20\x20\x20\x20\x73\x65\x74\x75\x70\x5f\x76\x61\x6c\x75\x65\x20\x22\x24\x7b\x6b\x65\x79\x7d\x22\x20\x22\x24\x7b\x76\x61\x6c\x75\x65\x7d\x22\x20\x22\x24\x7b\x66\x69\x6c\x65\x7d\x22\x0a\x20\x20\x65\x6c\x73\x65\x0a\x20\x20\x20\x20\x65\x63\x68\x6f\x20\x22\x24\x7b\x6b\x65\x79\x7d\x3d\x24\x7b\x76\x61\x6c\x75\x65\x7d\x22\x20\x7c\x20\x74\x65\x65\x20\x2d\x61\x20\x22\x24\x7b\x66\x69\x6c\x65\x7d\x22\x20\x3e\x2f\x64\x65\x76\x2f\x6e\x75\x6c\x6c\x0a\x20\x20\x66\x69\x0a\x7d\x0a\x0a\x61\x75\x74\x6f\x5f\x62\x61\x6c\x61\x6e\x63\x65\x72\x5f\x73\x65\x74\x74\x69\x6e\x67\x5f\x66\x6f\x72\x5f\x61\x6c\x6c\x28\x29\x20\x7b\x0a\x20\x20\x20\x20\x66\x69\x6c\x65\x5f\x6e\x61\x6d\x65\x3d\x24\x31\x0a\x20\x20\x20\x20\x61\x64\x64\x5f\x6f\x72\x5f\x73\x65\x74\x75\x70\x5f\x76\x61\x6c\x75\x65\x20\x22\x61\x75\x74\x6f\x62\x61\x6c\x61\x6e\x63\x65\x72\x2e\x74\x6f\x70\x69\x63\x22\x20\x22\x41\x75\x74\x6f\x42\x61\x6c\x61\x6e\x63\x65\x72\x4d\x65\x74\x72\x69\x63\x73\x52\x65\x70\x6f\x72\x74\x65\x72\x54\x6f\x70\x69\x63\x22\x20\x22\x24\x7b\x66\x69\x6c\x65\x5f\x6e\x61\x6d\x65\x7d\x22\x0a\x20\x20\x20\x20\x61\x64\x64\x5f\x6f\x72\x5f\x73\x65\x74\x75\x70\x5f\x76\x61\x6c\x75\x65\x20\x22\x61\x75\x74\x6f\x62\x61\x6c\x61\x6e\x63\x65\x72\x2e\x74\x6f\x70\x69\x63\x2e\x6e\x75\x6d\x2e\x70\x61\x72\x74\x69\x74\x69\x6f\x6e\x73\x22\x20\x22\x31\x22\x20\x22\x24\x7b\x66\x69\x6c\x65\x5f\x6e\x61\x6d\x65\x7d\x22\x0a\x7d\x0a\x0a\x61\x75\x74\x6f\x5f\x62\x61\x6c\x61\x6e\x63\x65\x72\x5f\x73\x65\x74\x74\x69\x6e\x67\x5f\x66\x6f\x72\x5f\x63\x6f\x6e\x74\x72\x6f\x6c\x6c\x65\x72\x5f\x6f\x6e\x6c\x79\x28\x29\x20\x7b\x0a\x20\x20\x20\x20\x66\x69\x6c\x65\x5f\x6e\x61\x6d\x65\x3d\x24\x31\x0a\x20\x20\x20\x20\x61\x64\x64\x5f\x6f\x72\x5f\x73\x65\x74\x75\x70\x5f\x76\x61\x6c\x75\x65\x20\x22\x61\x75\x74\x6f\x62\x61\x6c\x61\x6e\x63\x65\x72\x2e\x63\x6f\x6e\x74\x72\x6f\x6c\x6c\x65\x72\x2e\x65\x6e\x61\x62\x6c\x65\x22\x20\x22\x74\x72\x75\x65\x22\x20\x22\x24\x7b\x66\x69\x6c\x65\x5f\x6e\x61\x6d\x65\x7d\x22\x0a\x20\x20\x20\x20\x61\x64\x64\x5f\x6f\x72\x5f\x73\x65\x74\x75\x70\x5f\x76\x61\x6c\x75\x65\x20\x22\x61\x75\x74\x6f\x62\x61\x6c\x61\x6e\x63\x65\x72\x2e\x63\x6f\x6e\x74\x72\x6f\x6c\x6c\x65\x72\x2e\x65\x78\x63\x6c\x75\x64\x65\x2e\x74\x6f\x70\x69\x63\x73\x22\x20\x22\x5f\x5f\x63\x6f\x6e\x73\x75\x6d\x65\x72\x5f\x6f\x66\x66\x73\x65\x74\x73\x22\x20\x22\x24\x7b\x66\x69\x6c\x65\x5f\x6e\x61\x6d\x65\x7d\x22\x0a\x7d\x0a\x0a\x61\x75\x74\x6f\x5f\x62\x61\x6c\x61\x6e\x63\x65\x72\x5f\x73\x65\x74\x74\x69\x6e\x67\x5f\x66\x6f\x72\x5f\x62\x72\x6f\x6b\x65\x72\x5f\x6f\x6e\x6c\x79\x28\x29\x20\x7b\x0a\x20\x20\x20\x20\x66\x69\x6c\x65\x5f\x6e\x61\x6d\x65\x3d\x24\x31\x0a\x20\x20\x20\x20\x61\x64\x64\x5f\x6f\x72\x5f\x73\x65\x74\x75\x70\x5f\x76\x61\x6c\x75\x65\x20\x22\x6d\x65\x74\x72\x69\x63\x2e\x72\x65\x70\x6f\x72\x74\x65\x72\x73\x22\x20\x22\x6b\x61\x66\x6b\x61\x2e\x61\x75\x74\x6f\x62\x61\x6c\x61\x6e\x63\x65\x72\x2e\x6d\x65\x74\x72\x69\x63\x73\x72\x65\x70\x6f\x72\x74\x65\x72\x2e\x41\x75\x74\x6f\x42\x61\x6c\x61\x6e\x63\x65\x72\x4d\x65\x74\x72\x69\x63\x73\x52\x65\x70\x6f\x72\x74\x65\x72\x22\x20\x22\x24\x7b\x66\x69\x6c\x65\x5f\x6e\x61\x6d\x65\x7d\x22\x0a\x7d\x0a\x0a\x74\x75\x72\x6e\x5f\x6f\x6e\x5f\x61\x75\x74\x6f\x5f\x62\x61\x6c\x61\x6e\x63\x65\x72\x28\x29\x20\x7b\x0a\x20\x20\x20\x20\x72\x6f\x6c\x65\x3d\x24\x31\x0a\x20\x20\x20\x20\x66\x69\x6c\x65\x5f\x6e\x61\x6d\x65\x3d\x24\x32\x0a\x20\x20\x20\x20\x61\x75\x74\x6f\x5f\x62\x61\x6c\x61\x6e\x63\x65\x72\x5f\x73\x65\x74\x74\x69\x6e\x67\x5f\x66\x6f\x72\x5f\x61\x6c\x6c\x20\x22\x24\x7b\x66\x69\x6c\x65\x5f\x6e\x61\x6d\x65\x7d\x22\x0a\x20\x20\x20\x20\x69\x66\x20\x5b\x5b\x20\x22\x24\x7b\x72\x6f\x6c\x65\x7d\x22\x20\x3d\x3d\x20\x22\x62\x72\x6f\x6b\x65\x72\x22\x20\x5d\x5d\x3b\x20\x74\x68\x65\x6e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x61\x75\x74\x6f\x5f\x62\x61\x6c\x61\x6e\x63\x65\x72\x5f\x73\x65\x74\x74\x69\x6e\x67\x5f\x66\x6f\x72\x5f\x62\x72\x6f\x6b\x65\x72\x5f\x6f\x6e\x6c\x79\x20\x22\x24\x7b\x66\x69\x6c\x65\x5f\x6e\x61\x6d\x65\x7d\x22\x0a\x20\x20\x20\x20\x65\x6c\x69\x66\x20\x5b\x5b\x20\x22\x24\x7b\x72\x6f\x6c\x65\x7d\x22\x20\x3d\x3d\x20\x22\x63\x6f\x6e\x74\x72\x6f\x6c\x6c\x65\x72\x22\x20\x5d\x5d\x3b\x20\x74\x68\x65\x6e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x61\x75\x74\x6f\x5f\x62\x61\x6c\x61\x6e\x63\x65\x72\x5f\x73\x65\x74\x74\x69\x6e\x67\x5f\x66\x6f\x72\x5f\x63\x6f\x6e\x74\x72\x6f\x6c\x6c\x65\x72\x5f\x6f\x6e\x6c\x79\x20\x22\x24\x7b\x66\x69\x6c\x65\x5f\x6e\x61\x6d\x65\x7d\x22\x0a\x20\x20\x20\x20\x65\x6c\x69\x66\x20\x5b\x5b\x20\x22\x24\x7b\x72\x6f\x6c\x65\x7d\x22\x20\x3d\x3d\x20\x22\x73\x65\x72\x76\x65\x72\x22\x20\x5d\x5d\x3b\x20\x74\x68\x65\x6e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x61\x75\x74\x6f\x5f\x62\x61\x6c\x61\x6e\x63\x65\x72\x5f\x73\x65\x74\x74\x69\x6e\x67\x5f\x66\x6f\x72\x5f\x63\x6f\x6e\x74\x72\x6f\x6c\x6c\x65\x72\x5f\x6f\x6e\x6c\x79\x20\x22\x24\x7b\x66\x69\x6c\x65\x5f\x6e\x61\x6d\x65\x7d\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x61\x75\x74\x6f\x5f\x62\x61\x6c\x61\x6e\x63\x65\x72\x5f\x73\x65\x74\x74\x69\x6e\x67\x5f\x66\x6f\x72\x5f\x62\x72\x6f\x6b\x65\x72\x5f\x6f\x6e\x6c\x79\x20\x22\x24\x7b\x66\x69\x6c\x65\x5f\x6e\x61\x6d\x65\x7d\x22\x0a\x20\x20\x20\x20\x66\x69\x0a\x7d\x0a\x0a\x0a\x23\x20\x6d\x6f\x6e\x69\x74\x6f\x72\x20\x61\x6e\x64\x20\x63\x68\x61\x6e\x67\x65\x20\x61\x64\x76\x65\x72\x74\x69\x73\x65\x64\x20\x69\x70\x20\x66\x6f\x72\x20\x6b\x61\x66\x6b\x61\x0a\x6b\x61\x66\x6b\x61\x5f\x6d\x6f\x6e\x69\x74\x6f\x72\x5f\x69\x70\x28\x29\x20\x7b\x0a\x20\x20\x20\x20\x70\x72\x6f\x63\x65\x73\x73\x5f\x72\x6f\x6c\x65\x3d\x24\x28\x67\x72\x65\x70\x20\x22\x72\x6f\x6c\x65\x22\x20\x22\x24\x7b\x72\x75\x6e\x5f\x69\x6e\x66\x6f\x5f\x66\x69\x6c\x65\x7d\x22\x20\x7c\x20\x61\x77\x6b\x20\x2d\x46\x3d\x20\x27\x7b\x70\x72\x69\x6e\x74\x20\x24\x32\x7d\x27\x29\x0a\x20\x20\x20\x20\x5b\x5b\x20\x2d\x6e\x20\x22\x24\x7b\x70\x72\x6f\x63\x65\x73\x73\x5f\x72\x6f\x6c\x65\x7d\x22\x20\x5d\x5d\x20\x7c\x7c\x20\x64\x69\x65\x20\x22\x6b\x61\x66\x6b\x61\x5f\x64\x6f\x77\x6e\x3a\x20\x66\x61\x69\x6c\x65\x64\x20\x74\x6f\x20\x67\x65\x74\x20\x6e\x6f\x64\x65\x20\x72\x6f\x6c\x65\x22\x0a\x0a\x20\x20\x20\x20\x23\x20\x67\x65\x74\x20\x70\x72\x69\x76\x61\x74\x65\x20\x69\x70\x20\x66\x69\x72\x73\x74\x0a\x20\x20\x20\x20\x6c\x6f\x63\x61\x6c\x5f\x70\x72\x69\x76\x61\x74\x65\x5f\x69\x70\x3d\x24\x28\x68\x6f\x73\x74\x6e\x61\x6d\x65\x20\x2d\x49\x20\x7c\x20\x61\x77\x6b\x20\x27\x7b\x70\x72\x69\x6e\x74\x20\x24\x31\x7d\x27\x29\x0a\x20\x20\x20\x20\x69\x66\x20\x5b\x5b\x20\x22\x78\x24\x7b\x6c\x6f\x63\x61\x6c\x5f\x70\x72\x69\x76\x61\x74\x65\x5f\x69\x70\x7d\x22\x20\x3d\x3d\x20\x22\x78\x22\x20\x7c\x7c\x20\x22\x78\x24\x7b\x6c\x6f\x63\x61\x6c\x5f\x70\x72\x69\x76\x61\x74\x65\x5f\x69\x70\x7d\x22\x20\x3d\x3d\x20\x22\x78\x31\x32\x37\x2e\x30\x2e\x30\x2e\x31\x22\x20\x5d\x5d\x3b\x20\x74\x68\x65\x6e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x64\x69\x65\x20\x22\x6b\x61\x66\x6b\x61\x5f\x73\x74\x61\x72\x74\x5f\x75\x70\x3a\x20\x66\x61\x69\x6c\x65\x64\x20\x74\x6f\x20\x66\x69\x6e\x64\x20\x74\x68\x65\x20\x6c\x6f\x63\x61\x6c\x20\x70\x72\x69\x76\x61\x74\x65\x20\x49\x50\x20\x61\x64\x64\x72\x65\x73\x73\x2e\x22\x0a\x20\x20\x20\x20\x66\x69\x0a\x20\x20\x20\x20\x61\x64\x76\x65\x72\x74\x69\x73\x65\x64\x5f\x69\x70\x3d\x22\x24\x7b\x6c\x6f\x63\x61\x6c\x5f\x70\x72\x69\x76\x61\x74\x65\x5f\x69\x70\x7d\x22\x0a\x0a\x20\x20\x20\x20\x23\x20\x63\x68\x61\x6e\x67\x65\x20\x69\x70\x20\x73\x65\x74\x74\x69\x6e\x67\x73\x20\x66\x6f\x72\x20\x74\x68\x69\x73\x20\x6e\x6f\x64\x65\x0a\x20\x20\x20\x20\x69\x66\x20\x5b\x5b\x20\x22\x24\x7b\x70\x72\x6f\x63\x65\x73\x73\x5f\x72\x6f\x6c\x65\x7d\x22\x20\x3d\x3d\x20\x22\x73\x65\x72\x76\x65\x72\x22\x20\x5d\x5d\x3b\x20\x74\x68\x65\x6e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x74\x75\x70\x5f\x76\x61\x6c\x75\x65\x20\x22\x6c\x69\x73\x74\x65\x6e\x65\x72\x73\x22\x20\x22\x50\x4c\x41\x49\x4e\x54\x45\x58\x54\x3a\x2f\x2f\x24\x7b\x6c\x6f\x63\x61\x6c\x5f\x70\x72\x69\x76\x61\x74\x65\x5f\x69\x70\x7d\x3a\x39\x30\x39\x32\x2c\x43\x4f\x4e\x54\x52\x4f\x4c\x4c\x45\x52\x3a\x2f\x2f\x24\x7b\x6c\x6f\x63\x61\x6c\x5f\x70\x72\x69\x76\x61\x74\x65\x5f\x69\x70\x7d\x3a\x39\x30\x39\x33\x22\x20\x22\x24\x7b\x6b\x61\x66\x6b\x61\x5f\x64\x69\x72\x7d\x2f\x63\x6f\x6e\x66\x69\x67\x2f\x6b\x72\x61\x66\x74\x2f\x24\x7b\x70\x72\x6f\x63\x65\x73\x73\x5f\x72\x6f\x6c\x65\x7d\x2e\x70\x72\x6f\x70\x65\x72\x74\x69\x65\x73\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x74\x75\x70\x5f\x76\x61\x6c\x75\x65\x20\x22\x61\x64\x76\x65\x72\x74\x69\x73\x65\x64\x2e\x6c\x69\x73\x74\x65\x6e\x65\x72\x73\x22\x20\x22\x50\x4c\x41\x49\x4e\x54\x45\x58\x54\x3a\x2f\x2f\x24\x7b\x61\x64\x76\x65\x72\x74\x69\x73\x65\x64\x5f\x69\x70\x7d\x3a\x39\x30\x39\x32\x22\x20\x22\x24\x7b\x6b\x61\x66\x6b\x61\x5f\x64\x69\x72\x7d\x2f\x63\x6f\x6e\x66\x69\x67\x2f\x6b\x72\x61\x66\x74\x2f\x24\x7b\x70\x72\x6f\x63\x65\x73\x73\x5f\x72\x6f\x6c\x65\x7d\x2e\x70\x72\x6f\x70\x65\x72\x74\x69\x65\x73\x22\x0a\x20\x20\x20\x20\x65\x6c\x69\x66\x20\x5b\x5b\x20\x22\x24\x7b\x70\x72\x6f\x63\x65\x73\x73\x5f\x72\x6f\x6c\x65\x7d\x22\x20\x3d\x3d\x20\x22\x62\x72\x6f\x6b\x65\x72\x22\x20\x5d\x5d\x3b\x20\x74\x68\x65\x6e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x74\x75\x70\x5f\x76\x61\x6c\x75\x65\x20\x22\x6c\x69\x73\x74\x65\x6e\x65\x72\x73\x22\x20\x22\x50\x4c\x41\x49\x4e\x54\x45\x58\x54\x3a\x2f\x2f\x24\x7b\x6c\x6f\x63\x61\x6c\x5f\x70\x72\x69\x76\x61\x74\x65\x5f\x69\x70\x7d\x3a\x39\x30\x39\x32\x22\x20\x22\x24\x7b\x6b\x61\x66\x6b\x61\x5f\x64\x69\x72\x7d\x2f\x63\x6f\x6e\x66\x69\x67\x2f\x6b\x72\x61\x66\x74\x2f\x24\x7b\x70\x72\x6f\x63\x65\x73\x73\x5f\x72\x6f\x6c\x65\x7d\x2e\x70\x72\x6f\x70\x65\x72\x74\x69\x65\x73\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x74\x75\x70\x5f\x76\x61\x6c\x75\x65\x20\x22\x61\x64\x76\x65\x72\x74\x69\x73\x65\x64\x2e\x6c\x69\x73\x74\x65\x6e\x65\x72\x73\x22\x20\x22\x50\x4c\x41\x49\x4e\x54\x45\x58\x54\x3a\x2f\x2f\x24\x7b\x61\x64\x76\x65\x72\x74\x69\x73\x65\x64\x5f\x69\x70\x7d\x3a\x39\x30\x39\x32\x22\x20\x22\x24\x7b\x6b\x61\x66\x6b\x61\x5f\x64\x69\x72\x7d\x2f\x63\x6f\x6e\x66\x69\x67\x2f\x6b\x72\x61\x66\x74\x2f\x24\x7b\x70\x72\x6f\x63\x65\x73\x73\x5f\x72\x6f\x6c\x65\x7d\x2e\x70\x72\x6f\x70\x65\x72\x74\x69\x65\x73\x22\x0a\x20\x20\x20\x20\x65\x6c\x69\x66\x20\x5b\x5b\x20\x22\x24\x7b\x70\x72\x6f\x63\x65\x73\x73\x5f\x72\x6f\x6c\x65\x7d\x22\x20\x3d\x3d\x20\x22\x63\x6f\x6e\x74\x72\x6f\x6c\x6c\x65\x72\x22\x20\x5d\x5d\x3b\x20\x74\x68\x65\x6e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x74\x75\x70\x5f\x76\x61\x6c\x75\x65\x20\x22\x6c\x69\x73\x74\x65\x6e\x65\x72\x73\x22\x20\x22\x43\x4f\x4e\x54\x52\x4f\x4c\x4c\x45\x52\x3a\x2f\x2f\x24\x7b\x6c\x6f\x63\x61\x6c\x5f\x70\x72\x69\x76\x61\x74\x65\x5f\x69\x70\x7d\x3a\x39\x30\x39\x33\x22\x20\x22\x24\x7b\x6b\x61\x66\x6b\x61\x5f\x64\x69\x72\x7d\x2f\x63\x6f\x6e\x66\x69\x67\x2f\x6b\x72\x61\x66\x74\x2f\x24\x7b\x70\x72\x6f\x63\x65\x73\x73\x5f\x72\x6f\x6c\x65\x7d\x2e\x70\x72\x6f\x70\x65\x72\x74\x69\x65\x73\x22\x0a\x20\x20\x20\x20\x65\x6c\x73\x65\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x64\x69\x65\x20\x22\x6b\x61\x66\x6b\x61\x5f\x6d\x6f\x6e\x69\x74\x6f\x72\x5f\x69\x70\x3a\x20\x75\x6e\x6b\x6e\x6f\x77\x6e\x20\x70\x72\x6f\x63\x65\x73\x73\x20\x72\x6f\x6c\x65\x20\x24\x7b\x70\x72\x6f\x63\x65\x73\x73\x5f\x72\x6f\x6c\x65\x7d\x22\x0a\x20\x20\x20\x20\x66\x69\x0a\x7d\x0a\x0a\x63\x6f\x6e\x66\x69\x67\x75\x72\x65\x5f\x66\x72\x6f\x6d\x5f\x65\x6e\x76\x69\x72\x6f\x6e\x6d\x65\x6e\x74\x5f\x76\x61\x72\x69\x61\x62\x6c\x65\x73\x28\x29\x20\x7b\x0a\x20\x20\x20\x20\x66\x69\x6c\x65\x5f\x6e\x61\x6d\x65\x3d\x24\x31\x0a\x20\x20\x20\x20\x23\x20\x4c\x69\x73\x74\x20\x6f\x66\x20\x73\x70\x65\x63\x69\x61\x6c\x20\x63\x61\x73\x65\x73\x20\x74\x6f\x20\x61\x70\x70\x6c\x79\x20\x74\x6f\x20\x74\x68\x65\x20\x76\x61\x72\x69\x61\x62\x6c\x65\x73\x0a\x20\x20\x20\x20\x6c\x6f\x63\x61\x6c\x20\x2d\x72\x20\x65\x78\x63\x65\x70\x74\x69\x6f\x6e\x5f\x72\x65\x67\x65\x78\x70\x73\x3d\x28\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x22\x73\x2f\x73\x61\x73\x6c\x5c\x2e\x73\x73\x6c\x2f\x73\x61\x73\x6c\x5f\x73\x73\x6c\x2f\x67\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x22\x73\x2f\x73\x61\x73\x6c\x5c\x2e\x70\x6c\x61\x69\x6e\x74\x65\x78\x74\x2f\x73\x61\x73\x6c\x5f\x70\x6c\x61\x69\x6e\x74\x65\x78\x74\x2f\x67\x22\x0a\x20\x20\x20\x20\x29\x0a\x20\x20\x20\x20\x23\x20\x4d\x61\x70\x20\x65\x6e\x76\x69\x72\x6f\x6e\x6d\x65\x6e\x74\x20\x76\x61\x72\x69\x61\x62\x6c\x65\x73\x20\x74\x6f\x20\x63\x6f\x6e\x66\x69\x67\x20\x70\x72\x6f\x70\x65\x72\x74\x69\x65\x73\x0a\x20\x20\x20\x20\x66\x6f\x72\x20\x76\x61\x72\x20\x69\x6e\x20\x22\x24\x7b\x21\x4b\x41\x46\x4b\x41\x5f\x43\x46\x47\x5f\x40\x7d\x22\x3b\x20\x64\x6f\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x6b\x65\x79\x3d\x22\x24\x28\x65\x63\x68\x6f\x20\x22\x24\x76\x61\x72\x22\x20\x7c\x20\x73\x65\x64\x20\x2d\x65\x20\x27\x73\x2f\x5e\x4b\x41\x46\x4b\x41\x5f\x43\x46\x47\x5f\x2f\x2f\x67\x27\x20\x2d\x65\x20\x27\x73\x2f\x5f\x2f\x5c\x2e\x2f\x67\x27\x20\x7c\x20\x74\x72\x20\x27\x5b\x3a\x75\x70\x70\x65\x72\x3a\x5d\x27\x20\x27\x5b\x3a\x6c\x6f\x77\x65\x72\x3a\x5d\x27\x29\x22\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x23\x20\x45\x78\x63\x65\x70\x74\x69\x6f\x6e\x20\x66\x6f\x72\x20\x74\x68\x65\x20\x63\x61\x6d\x65\x6c\x20\x63\x61\x73\x65\x20\x69\x6e\x20\x74\x68\x69\x73\x20\x65\x6e\x76\x69\x72\x6f\x6e\x6d\x65\x6e\x74\x20\x76\x61\x72\x69\x61\x62\x6c\x65\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x5b\x5b\x20\x22\x24\x76\x61\x72\x22\x20\x3d\x3d\x20\x22\x4b\x41\x46\x4b\x41\x5f\x43\x46\x47\x5f\x5a\x4f\x4f\x4b\x45\x45\x50\x45\x52\x5f\x43\x4c\x49\x45\x4e\x54\x43\x4e\x58\x4e\x53\x4f\x43\x4b\x45\x54\x22\x20\x5d\x5d\x20\x26\x26\x20\x6b\x65\x79\x3d\x22\x7a\x6f\x6f\x6b\x65\x65\x70\x65\x72\x2e\x63\x6c\x69\x65\x6e\x74\x43\x6e\x78\x6e\x53\x6f\x63\x6b\x65\x74\x22\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x23\x20\x41\x70\x70\x6c\x79\x20\x65\x78\x63\x65\x70\x74\x69\x6f\x6e\x20\x72\x65\x67\x65\x78\x70\x73\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x66\x6f\x72\x20\x72\x65\x67\x65\x78\x20\x69\x6e\x20\x22\x24\x7b\x65\x78\x63\x65\x70\x74\x69\x6f\x6e\x5f\x72\x65\x67\x65\x78\x70\x73\x5b\x40\x5d\x7d\x22\x3b\x20\x64\x6f\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x6b\x65\x79\x3d\x22\x24\x28\x65\x63\x68\x6f\x20\x22\x24\x6b\x65\x79\x22\x20\x7c\x20\x73\x65\x64\x20\x22\x24\x72\x65\x67\x65\x78\x22\x29\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x64\x6f\x6e\x65\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x76\x61\x6c\x75\x65\x3d\x22\x24\x7b\x21\x76\x61\x72\x7d\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x61\x64\x64\x5f\x6f\x72\x5f\x73\x65\x74\x75\x70\x5f\x76\x61\x6c\x75\x65\x20\x22\x24\x7b\x6b\x65\x79\x7d\x22\x20\x22\x24\x7b\x76\x61\x6c\x75\x65\x7d\x22\x20\x22\x24\x7b\x66\x69\x6c\x65\x5f\x6e\x61\x6d\x65\x7d\x22\x0a\x20\x20\x20\x20\x64\x6f\x6e\x65\x0a\x7d\x0a\x0a\x6b\x61\x66\x6b\x61\x5f\x75\x70\x28\x29\x20\x7b\x0a\x20\x20\x65\x63\x68\x6f\x20\x22\x6b\x61\x66\x6b\x61\x5f\x75\x70\x3a\x20\x73\x74\x61\x72\x74\x22\x0a\x0a\x20\x20\x77\x68\x69\x6c\x65\x20\x5b\x5b\x20\x24\x23\x20\x2d\x67\x65\x20\x31\x20\x5d\x5d\x3b\x20\x64\x6f\x0a\x20\x20\x20\x20\x20\x20\x63\x61\x73\x65\x20\x22\x24\x7b\x31\x7d\x22\x20\x69\x6e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x2d\x2d\x70\x72\x6f\x63\x65\x73\x73\x2e\x72\x6f\x6c\x65\x73\x29\x20\x73\x65\x74\x5f\x6f\x6e\x63\x65\x20\x70\x72\x6f\x63\x65\x73\x73\x5f\x72\x6f\x6c\x65\x20\x22\x24\x7b\x32\x7d\x22\x20\x22\x72\x6f\x6c\x65\x20\x6f\x66\x20\x74\x68\x69\x73\x20\x6e\x6f\x64\x65\x22\x3b\x20\x73\x68\x69\x66\x74\x20\x32\x3b\x3b\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x2d\x2d\x6e\x6f\x64\x65\x2e\x69\x64\x29\x20\x73\x65\x74\x5f\x6f\x6e\x63\x65\x20\x6e\x6f\x64\x65\x5f\x69\x64\x20\x22\x24\x7b\x32\x7d\x22\x20\x22\x69\x64\x20\x6f\x66\x20\x74\x68\x69\x73\x20\x6e\x6f\x64\x65\x22\x3b\x20\x73\x68\x69\x66\x74\x20\x32\x3b\x3b\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x2d\x2d\x63\x6f\x6e\x74\x72\x6f\x6c\x6c\x65\x72\x2e\x71\x75\x6f\x72\x75\x6d\x2e\x76\x6f\x74\x65\x72\x73\x29\x20\x73\x65\x74\x5f\x6f\x6e\x63\x65\x20\x71\x75\x6f\x72\x75\x6d\x5f\x76\x6f\x74\x65\x72\x73\x20\x22\x24\x7b\x32\x7d\x22\x20\x22\x63\x6f\x6e\x74\x72\x6f\x6c\x6c\x65\x72\x20\x71\x75\x6f\x72\x75\x6d\x20\x76\x6f\x74\x65\x72\x73\x22\x3b\x20\x73\x68\x69\x66\x74\x20\x32\x3b\x3b\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x2d\x2d\x73\x33\x2e\x72\x65\x67\x69\x6f\x6e\x29\x20\x73\x65\x74\x5f\x6f\x6e\x63\x65\x20\x73\x33\x5f\x72\x65\x67\x69\x6f\x6e\x20\x22\x24\x7b\x32\x7d\x22\x20\x22\x72\x65\x67\x69\x6f\x6e\x73\x20\x6f\x66\x20\x73\x33\x22\x3b\x20\x73\x68\x69\x66\x74\x20\x32\x3b\x3b\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x2d\x2d\x73\x33\x2e\x62\x75\x63\x6b\x65\x74\x29\x20\x73\x65\x74\x5f\x6f\x6e\x63\x65\x20\x73\x33\x5f\x62\x75\x63\x6b\x65\x74\x20\x22\x24\x7b\x32\x7d\x22\x20\x22\x62\x75\x63\x6b\x65\x74\x20\x6e\x61\x6d\x65\x20\x6f\x66\x20\x73\x33\x22\x3b\x20\x73\x68\x69\x66\x74\x20\x32\x3b\x3b\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x2d\x2d\x63\x6c\x75\x73\x74\x65\x72\x2e\x69\x64\x29\x20\x73\x65\x74\x5f\x6f\x6e\x63\x65\x20\x63\x6c\x75\x73\x74\x65\x72\x5f\x69\x64\x20\x22\x24\x7b\x32\x7d\x22\x20\x22\x6b\x61\x66\x6b\x61\x20\x63\x6c\x75\x73\x74\x65\x72\x20\x69\x64\x22\x3b\x20\x73\x68\x69\x66\x74\x20\x32\x3b\x3b\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x2d\x2d\x73\x33\x2e\x61\x63\x63\x65\x73\x73\x2e\x6b\x65\x79\x29\x20\x73\x65\x74\x5f\x6f\x6e\x63\x65\x20\x73\x33\x5f\x61\x63\x63\x65\x73\x73\x5f\x6b\x65\x79\x20\x22\x24\x7b\x32\x7d\x22\x20\x22\x73\x33\x20\x61\x63\x63\x65\x73\x73\x20\x6b\x65\x79\x22\x3b\x20\x73\x68\x69\x66\x74\x20\x32\x3b\x3b\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x2d\x2d\x73\x33\x2e\x73\x65\x63\x72\x65\x74\x2e\x6b\x65\x79\x29\x20\x73\x65\x74\x5f\x6f\x6e\x63\x65\x20\x73\x33\x5f\x73\x65\x63\x72\x65\x74\x5f\x6b\x65\x79\x20\x22\x24\x7b\x32\x7d\x22\x20\x22\x73\x33\x20\x73\x65\x63\x72\x65\x74\x20\x6b\x65\x79\x22\x3b\x20\x73\x68\x69\x66\x74\x20\x32\x3b\x3b\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x2d\x2d\x73\x33\x2e\x65\x6e\x64\x70\x6f\x69\x6e\x74\x29\x20\x73\x65\x74\x5f\x6f\x6e\x63\x65\x20\x73\x33\x5f\x65\x6e\x64\x70\x6f\x69\x6e\x74\x20\x22\x24\x7b\x32\x7d\x22\x20\x22\x73\x33\x20\x65\x6e\x64\x70\x6f\x69\x6e\x74\x22\x3b\x20\x73\x68\x69\x66\x74\x20\x32\x3b\x3b\x0a\x20\x20\x20\x20\x20\x20\x65\x73\x61\x63\x0a\x20\x20\x64\x6f\x6e\x65\x0a\x0a\x20\x20\x70\x69\x64\x3d\x24\x28\x6a\x63\x6d\x64\x20\x7c\x20\x67\x72\x65\x70\x20\x2d\x65\x20\x6b\x61\x66\x6b\x61\x2e\x4b\x61\x66\x6b\x61\x20\x7c\x20\x61\x77\x6b\x20\x27\x7b\x70\x72\x69\x6e\x74\x20\x24\x31\x7d\x27\x29\x0a\x20\x20\x69\x66\x20\x5b\x5b\x20\x2d\x6e\x20\x22\x24\x7b\x70\x69\x64\x7d\x22\x20\x5d\x5d\x3b\x20\x74\x68\x65\x6e\x0a\x20\x20\x20\x20\x20\x20\x65\x63\x68\x6f\x20\x22\x6b\x61\x66\x6b\x61\x5f\x75\x70\x3a\x20\x6b\x61\x66\x6b\x61\x20\x69\x73\x20\x61\x6c\x72\x65\x61\x64\x79\x20\x72\x75\x6e\x6e\x69\x6e\x67\x2c\x20\x70\x69\x64\x3d\x24\x7b\x70\x69\x64\x7d\x22\x0a\x20\x20\x20\x20\x20\x20\x65\x78\x69\x74\x20\x30\x0a\x20\x20\x66\x69\x0a\x0a\x20\x20\x5b\x5b\x20\x2d\x6e\x20\x22\x24\x7b\x6e\x6f\x64\x65\x5f\x69\x64\x7d\x22\x20\x5d\x5d\x20\x7c\x7c\x20\x64\x69\x65\x20\x22\x6e\x6f\x64\x65\x5f\x69\x64\x20\x69\x73\x20\x65\x6d\x70\x74\x79\x22\x0a\x20\x20\x5b\x5b\x20\x2d\x6e\x20\x22\x24\x7b\x70\x72\x6f\x63\x65\x73\x73\x5f\x72\x6f\x6c\x65\x7d\x22\x20\x5d\x5d\x20\x7c\x7c\x20\x64\x69\x65\x20\x22\x70\x72\x6f\x63\x65\x73\x73\x5f\x72\x6f\x6c\x65\x20\x69\x73\x20\x65\x6d\x70\x74\x79\x22\x0a\x20\x20\x5b\x5b\x20\x2d\x6e\x20\x22\x24\x7b\x71\x75\x6f\x72\x75\x6d\x5f\x76\x6f\x74\x65\x72\x73\x7d\x22\x20\x5d\x5d\x20\x7c\x7c\x20\x64\x69\x65\x20\x22\x71\x75\x6f\x72\x75\x6d\x5f\x76\x6f\x74\x65\x72\x73\x20\x69\x73\x20\x65\x6d\x70\x74\x79\x22\x0a\x20\x20\x5b\x5b\x20\x2d\x6e\x20\x22\x24\x7b\x73\x33\x5f\x72\x65\x67\x69\x6f\x6e\x7d\x22\x20\x5d\x5d\x20\x7c\x7c\x20\x73\x33\x5f\x72\x65\x67\x69\x6f\x6e\x3d\x22\x24\x7b\x41\x57\x53\x5f\x44\x45\x46\x41\x55\x4c\x54\x5f\x52\x45\x47\x49\x4f\x4e\x7d\x22\x0a\x20\x20\x5b\x5b\x20\x2d\x6e\x20\x22\x24\x7b\x73\x33\x5f\x62\x75\x63\x6b\x65\x74\x7d\x22\x20\x5d\x5d\x20\x7c\x7c\x20\x64\x69\x65\x20\x22\x73\x33\x5f\x62\x75\x63\x6b\x65\x74\x20\x69\x73\x20\x65\x6d\x70\x74\x79\x22\x0a\x20\x20\x5b\x5b\x20\x2d\x6e\x20\x22\x24\x7b\x73\x33\x5f\x61\x63\x63\x65\x73\x73\x5f\x6b\x65\x79\x7d\x22\x20\x5d\x5d\x20\x7c\x7c\x20\x73\x33\x5f\x61\x63\x63\x65\x73\x73\x5f\x6b\x65\x79\x3d\x22\x24\x7b\x4b\x41\x46\x4b\x41\x5f\x53\x33\x5f\x41\x43\x43\x45\x53\x53\x5f\x4b\x45\x59\x7d\x22\x0a\x20\x20\x5b\x5b\x20\x2d\x6e\x20\x22\x24\x7b\x73\x33\x5f\x73\x65\x63\x72\x65\x74\x5f\x6b\x65\x79\x7d\x22\x20\x5d\x5d\x20\x7c\x7c\x20\x73\x33\x5f\x73\x65\x63\x72\x65\x74\x5f\x6b\x65\x79\x3d\x22\x24\x7b\x4b\x41\x46\x4b\x41\x5f\x53\x33\x5f\x53\x45\x43\x52\x45\x54\x5f\x4b\x45\x59\x7d\x22\x0a\x20\x20\x5b\x5b\x20\x2d\x6e\x20\x22\x24\x7b\x73\x33\x5f\x65\x6e\x64\x70\x6f\x69\x6e\x74\x7d\x22\x20\x5d\x5d\x20\x7c\x7c\x20\x64\x69\x65\x20\x22\x73\x33\x5f\x65\x6e\x64\x70\x6f\x69\x6e\x74\x20\x69\x73\x20\x65\x6d\x70\x74\x79\x22\x0a\x20\x20\x5b\x5b\x20\x2d\x6e\x20\x22\x24\x7b\x63\x6c\x75\x73\x74\x65\x72\x5f\x69\x64\x7d\x22\x20\x5d\x5d\x20\x7c\x7c\x20\x63\x6c\x75\x73\x74\x65\x72\x5f\x69\x64\x3d\x22\x72\x5a\x64\x45\x30\x44\x6a\x5a\x53\x72\x71\x79\x39\x36\x50\x58\x72\x4d\x55\x5a\x56\x77\x22\x0a\x0a\x20\x20\x66\x6f\x72\x20\x72\x6f\x6c\x65\x20\x69\x6e\x20\x22\x62\x72\x6f\x6b\x65\x72\x22\x20\x22\x63\x6f\x6e\x74\x72\x6f\x6c\x6c\x65\x72\x22\x20\x22\x73\x65\x72\x76\x65\x72\x22\x3b\x20\x64\x6f\x0a\x20\x20\x20\x20\x20\x20\x73\x65\x74\x75\x70\x5f\x76\x61\x6c\x75\x65\x20\x22\x6e\x6f\x64\x65\x2e\x69\x64\x22\x20\x22\x24\x7b\x6e\x6f\x64\x65\x5f\x69\x64\x7d\x22\x20\x22\x24\x7b\x6b\x61\x66\x6b\x61\x5f\x64\x69\x72\x7d\x2f\x63\x6f\x6e\x66\x69\x67\x2f\x6b\x72\x61\x66\x74\x2f\x24\x7b\x72\x6f\x6c\x65\x7d\x2e\x70\x72\x6f\x70\x65\x72\x74\x69\x65\x73\x22\x0a\x20\x20\x20\x20\x20\x20\x73\x65\x74\x75\x70\x5f\x76\x61\x6c\x75\x65\x20\x22\x63\x6f\x6e\x74\x72\x6f\x6c\x6c\x65\x72\x2e\x71\x75\x6f\x72\x75\x6d\x2e\x76\x6f\x74\x65\x72\x73\x22\x20\x22\x24\x7b\x71\x75\x6f\x72\x75\x6d\x5f\x76\x6f\x74\x65\x72\x73\x7d\x22\x20\x22\x24\x7b\x6b\x61\x66\x6b\x61\x5f\x64\x69\x72\x7d\x2f\x63\x6f\x6e\x66\x69\x67\x2f\x6b\x72\x61\x66\x74\x2f\x24\x7b\x72\x6f\x6c\x65\x7d\x2e\x70\x72\x6f\x70\x65\x72\x74\x69\x65\x73\x22\x0a\x20\x20\x20\x20\x20\x20\x73\x65\x74\x75\x70\x5f\x76\x61\x6c\x75\x65\x20\x22\x73\x33\x2e\x64\x61\x74\x61\x2e\x62\x75\x63\x6b\x65\x74\x22\x20\x22\x30\x40\x73\x33\x3a\x2f\x2f\x24\x7b\x73\x33\x5f\x62\x75\x63\x6b\x65\x74\x7d\x3f\x72\x65\x67\x69\x6f\x6e\x3d\x24\x7b\x73\x33\x5f\x72\x65\x67\x69\x6f\x6e\x7d\x26\x65\x6e\x64\x70\x6f\x69\x6e\x74\x3d\x24\x7b\x73\x33\x5f\x65\x6e\x64\x70\x6f\x69\x6e\x74\x7d\x26\x61\x63\x63\x65\x73\x73\x4b\x65\x79\x3d\x73\x74\x61\x74\x69\x63\x22\x20\x22\x24\x7b\x6b\x61\x66\x6b\x61\x5f\x64\x69\x72\x7d\x2f\x63\x6f\x6e\x66\x69\x67\x2f\x6b\x72\x61\x66\x74\x2f\x24\x7b\x72\x6f\x6c\x65\x7d\x2e\x70\x72\x6f\x70\x65\x72\x74\x69\x65\x73\x22\x0a\x20\x20\x20\x20\x20\x20\x73\x65\x74\x75\x70\x5f\x76\x61\x6c\x75\x65\x20\x22\x73\x33\x2e\x6f\x70\x73\x2e\x62\x75\x63\x6b\x65\x74\x22\x20\x22\x30\x40\x73\x33\x3a\x2f\x2f\x24\x7b\x73\x33\x5f\x62\x75\x63\x6b\x65\x74\x7d\x3f\x72\x65\x67\x69\x6f\x6e\x3d\x24\x7b\x73\x33\x5f\x72\x65\x67\x69\x6f\x6e\x7d\x26\x65\x6e\x64\x70\x6f\x69\x6e\x74\x3d\x24\x7b\x73\x33\x5f\x65\x6e\x64\x70\x6f\x69\x6e\x74\x7d\x26\x61\x63\x63\x65\x73\x73\x4b\x65\x79\x3d\x73\x74\x61\x74\x69\x63\x22\x20\x22\x24\x7b\x6b\x61\x66\x6b\x61\x5f\x64\x69\x72\x7d\x2f\x63\x6f\x6e\x66\x69\x67\x2f\x6b\x72\x61\x66\x74\x2f\x24\x7b\x72\x6f\x6c\x65\x7d\x2e\x70\x72\x6f\x70\x65\x72\x74\x69\x65\x73\x22\x0a\x20\x20\x20\x20\x20\x20\x73\x65\x74\x75\x70\x5f\x76\x61\x6c\x75\x65\x20\x22\x6c\x6f\x67\x2e\x64\x69\x72\x73\x22\x20\x22\x24\x7b\x64\x61\x74\x61\x5f\x70\x61\x74\x68\x7d\x2f\x6b\x72\x61\x66\x74\x2d\x24\x7b\x72\x6f\x6c\x65\x7d\x2d\x6c\x6f\x67\x73\x22\x20\x22\x24\x7b\x6b\x61\x66\x6b\x61\x5f\x64\x69\x72\x7d\x2f\x63\x6f\x6e\x66\x69\x67\x2f\x6b\x72\x61\x66\x74\x2f\x24\x7b\x72\x6f\x6c\x65\x7d\x2e\x70\x72\x6f\x70\x65\x72\x74\x69\x65\x73\x22\x0a\x20\x20\x20\x20\x20\x20\x73\x65\x74\x75\x70\x5f\x76\x61\x6c\x75\x65\x20\x22\x73\x33\x2e\x77\x61\x6c\x2e\x70\x61\x74\x68\x22\x20\x22\x30\x40\x66\x69\x6c\x65\x3a\x2f\x2f\x24\x7b\x64\x61\x74\x61\x5f\x70\x61\x74\x68\x7d\x2f\x77\x61\x6c\x3f\x63\x61\x70\x61\x63\x69\x74\x79\x3d\x32\x31\x34\x37\x34\x38\x33\x36\x34\x38\x22\x20\x22\x24\x7b\x6b\x61\x66\x6b\x61\x5f\x64\x69\x72\x7d\x2f\x63\x6f\x6e\x66\x69\x67\x2f\x6b\x72\x61\x66\x74\x2f\x24\x7b\x72\x6f\x6c\x65\x7d\x2e\x70\x72\x6f\x70\x65\x72\x74\x69\x65\x73\x22\x0a\x20\x20\x20\x20\x20\x20\x23\x20\x74\x75\x72\x6e\x20\x6f\x6e\x20\x61\x75\x74\x6f\x5f\x62\x61\x6c\x61\x6e\x63\x65\x72\x0a\x20\x20\x20\x20\x20\x20\x74\x75\x72\x6e\x5f\x6f\x6e\x5f\x61\x75\x74\x6f\x5f\x62\x61\x6c\x61\x6e\x63\x65\x72\x20\x22\x24\x7b\x72\x6f\x6c\x65\x7d\x22\x20\x22\x24\x7b\x6b\x61\x66\x6b\x61\x5f\x64\x69\x72\x7d\x2f\x63\x6f\x6e\x66\x69\x67\x2f\x6b\x72\x61\x66\x74\x2f\x24\x7b\x72\x6f\x6c\x65\x7d\x2e\x70\x72\x6f\x70\x65\x72\x74\x69\x65\x73\x22\x0a\x20\x20\x64\x6f\x6e\x65\x0a\x0a\x20\x20\x69\x66\x20\x5b\x5b\x20\x2d\x6e\x20\x22\x24\x7b\x4b\x41\x46\x4b\x41\x5f\x48\x45\x41\x50\x5f\x4f\x50\x54\x53\x7d\x22\x20\x5d\x5d\x3b\x20\x74\x68\x65\x6e\x0a\x20\x20\x20\x20\x20\x20\x6b\x61\x66\x6b\x61\x5f\x68\x65\x61\x70\x5f\x6f\x70\x74\x73\x3d\x22\x24\x7b\x4b\x41\x46\x4b\x41\x5f\x48\x45\x41\x50\x5f\x4f\x50\x54\x53\x7d\x22\x0a\x20\x20\x65\x6c\x69\x66\x20\x5b\x5b\x20\x22\x24\x7b\x70\x72\x6f\x63\x65\x73\x73\x5f\x72\x6f\x6c\x65\x7d\x22\x20\x3d\x3d\x20\x22\x62\x72\x6f\x6b\x65\x72\x22\x20\x7c\x7c\x20\x22\x24\x7b\x70\x72\x6f\x63\x65\x73\x73\x5f\x72\x6f\x6c\x65\x7d\x22\x20\x3d\x3d\x20\x22\x73\x65\x72\x76\x65\x72\x22\x20\x5d\x5d\x3b\x20\x74\x68\x65\x6e\x0a\x20\x20\x20\x20\x20\x20\x6b\x61\x66\x6b\x61\x5f\x68\x65\x61\x70\x5f\x6f\x70\x74\x73\x3d\x22\x2d\x58\x6d\x73\x31\x67\x20\x2d\x58\x6d\x78\x31\x67\x20\x2d\x58\x58\x3a\x4d\x65\x74\x61\x73\x70\x61\x63\x65\x53\x69\x7a\x65\x3d\x39\x36\x6d\x20\x2d\x58\x58\x3a\x4d\x61\x78\x44\x69\x72\x65\x63\x74\x4d\x65\x6d\x6f\x72\x79\x53\x69\x7a\x65\x3d\x31\x47\x22\x0a\x20\x20\x65\x6c\x69\x66\x20\x5b\x5b\x20\x22\x24\x7b\x70\x72\x6f\x63\x65\x73\x73\x5f\x72\x6f\x6c\x65\x7d\x22\x20\x3d\x3d\x20\x22\x63\x6f\x6e\x74\x72\x6f\x6c\x6c\x65\x72\x22\x20\x5d\x5d\x3b\x20\x74\x68\x65\x6e\x0a\x20\x20\x20\x20\x20\x20\x6b\x61\x66\x6b\x61\x5f\x68\x65\x61\x70\x5f\x6f\x70\x74\x73\x3d\x22\x2d\x58\x6d\x73\x31\x67\x20\x2d\x58\x6d\x78\x31\x67\x20\x2d\x58\x58\x3a\x4d\x65\x74\x61\x73\x70\x61\x63\x65\x53\x69\x7a\x65\x3d\x39\x36\x6d\x22\x0a\x20\x20\x65\x6c\x73\x65\x0a\x20\x20\x20\x20\x20\x20\x64\x69\x65\x20\x22\x6b\x61\x66\x6b\x61\x5f\x73\x74\x61\x72\x74\x5f\x75\x70\x3a\x20\x75\x6e\x6b\x6e\x6f\x77\x6e\x20\x70\x72\x6f\x63\x65\x73\x73\x20\x72\x6f\x6c\x65\x20\x24\x7b\x70\x72\x6f\x63\x65\x73\x73\x5f\x72\x6f\x6c\x65\x7d\x22\x0a\x20\x20\x66\x69\x0a\x0a\x20\x20\x23\x20\x61\x64\x64\x20\x74\x68\x69\x73\x20\x6e\x6f\x64\x65\x27\x73\x20\x69\x6e\x66\x6f\x20\x74\x6f\x20\x72\x75\x6e\x2e\x69\x6e\x66\x6f\x0a\x20\x20\x73\x65\x74\x75\x70\x5f\x76\x61\x6c\x75\x65\x20\x22\x6e\x6f\x64\x65\x2e\x69\x64\x22\x20\x22\x24\x7b\x6e\x6f\x64\x65\x5f\x69\x64\x7d\x22\x20\x22\x24\x7b\x72\x75\x6e\x5f\x69\x6e\x66\x6f\x5f\x66\x69\x6c\x65\x7d\x22\x0a\x20\x20\x73\x65\x74\x75\x70\x5f\x76\x61\x6c\x75\x65\x20\x22\x72\x6f\x6c\x65\x22\x20\x22\x24\x7b\x70\x72\x6f\x63\x65\x73\x73\x5f\x72\x6f\x6c\x65\x7d\x22\x20\x22\x24\x7b\x72\x75\x6e\x5f\x69\x6e\x66\x6f\x5f\x66\x69\x6c\x65\x7d\x22\x0a\x20\x20\x73\x65\x74\x75\x70\x5f\x76\x61\x6c\x75\x65\x20\x22\x6b\x61\x66\x6b\x61\x2e\x62\x61\x73\x65\x2e\x70\x61\x74\x68\x22\x20\x22\x24\x7b\x6b\x61\x66\x6b\x61\x5f\x64\x69\x72\x7d\x22\x20\x22\x24\x7b\x72\x75\x6e\x5f\x69\x6e\x66\x6f\x5f\x66\x69\x6c\x65\x7d\x22\x0a\x20\x20\x73\x65\x74\x75\x70\x5f\x76\x61\x6c\x75\x65\x20\x22\x6b\x61\x66\x6b\x61\x2e\x64\x61\x74\x61\x2e\x70\x61\x74\x68\x22\x20\x22\x24\x7b\x64\x61\x74\x61\x5f\x70\x61\x74\x68\x7d\x22\x20\x22\x24\x7b\x72\x75\x6e\x5f\x69\x6e\x66\x6f\x5f\x66\x69\x6c\x65\x7d\x22\x0a\x0a\x20\x20\x23\x20\x63\x68\x61\x6e\x67\x65\x20\x69\x70\x20\x73\x65\x74\x74\x69\x6e\x67\x73\x20\x68\x65\x72\x65\x0a\x20\x20\x6b\x61\x66\x6b\x61\x5f\x6d\x6f\x6e\x69\x74\x6f\x72\x5f\x69\x70\x0a\x20\x20\x65\x63\x68\x6f\x20\x22\x6b\x61\x66\x6b\x61\x5f\x75\x70\x3a\x20\x69\x70\x20\x73\x65\x74\x74\x69\x6e\x67\x73\x20\x63\x68\x61\x6e\x67\x65\x64\x22\x0a\x0a\x20\x20\x23\x20\x6f\x76\x65\x72\x72\x69\x64\x65\x20\x73\x65\x74\x74\x69\x6e\x67\x73\x20\x66\x72\x6f\x6d\x20\x65\x6e\x76\x0a\x20\x20\x63\x6f\x6e\x66\x69\x67\x75\x72\x65\x5f\x66\x72\x6f\x6d\x5f\x65\x6e\x76\x69\x72\x6f\x6e\x6d\x65\x6e\x74\x5f\x76\x61\x72\x69\x61\x62\x6c\x65\x73\x20\x22\x24\x7b\x6b\x61\x66\x6b\x61\x5f\x64\x69\x72\x7d\x2f\x63\x6f\x6e\x66\x69\x67\x2f\x6b\x72\x61\x66\x74\x2f\x24\x7b\x70\x72\x6f\x63\x65\x73\x73\x5f\x72\x6f\x6c\x65\x7d\x2e\x70\x72\x6f\x70\x65\x72\x74\x69\x65\x73\x22\x0a\x0a\x20\x20\x23\x20\x44\x69\x73\x61\x62\x6c\x65\x20\x74\x68\x65\x20\x64\x65\x66\x61\x75\x6c\x74\x20\x63\x6f\x6e\x73\x6f\x6c\x65\x20\x6c\x6f\x67\x67\x65\x72\x20\x69\x6e\x20\x66\x61\x76\x6f\x75\x72\x20\x6f\x66\x20\x4b\x61\x66\x6b\x61\x41\x70\x70\x65\x6e\x64\x65\x72\x20\x28\x77\x68\x69\x63\x68\x20\x70\x72\x6f\x76\x69\x64\x65\x73\x20\x74\x68\x65\x20\x65\x78\x61\x63\x74\x20\x6f\x75\x74\x70\x75\x74\x29\x0a\x20\x20\x65\x63\x68\x6f\x20\x22\x6c\x6f\x67\x34\x6a\x2e\x61\x70\x70\x65\x6e\x64\x65\x72\x2e\x73\x74\x64\x6f\x75\x74\x2e\x54\x68\x72\x65\x73\x68\x6f\x6c\x64\x3d\x4f\x46\x46\x22\x20\x3e\x3e\x20\x22\x24\x7b\x6b\x61\x66\x6b\x61\x5f\x64\x69\x72\x7d\x2f\x63\x6f\x6e\x66\x69\x67\x2f\x6c\x6f\x67\x34\x6a\x2e\x70\x72\x6f\x70\x65\x72\x74\x69\x65\x73\x22\x0a\x0a\x20\x20\x23\x20\x66\x6f\x72\x6d\x61\x74\x20\x74\x68\x65\x20\x64\x61\x74\x61\x20\x70\x61\x74\x68\x0a\x20\x20\x6d\x75\x73\x74\x5f\x64\x6f\x20\x2d\x76\x20\x22\x24\x7b\x6b\x61\x66\x6b\x61\x5f\x64\x69\x72\x7d\x2f\x62\x69\x6e\x2f\x6b\x61\x66\x6b\x61\x2d\x73\x74\x6f\x72\x61\x67\x65\x2e\x73\x68\x20\x66\x6f\x72\x6d\x61\x74\x20\x2d\x67\x20\x2d\x74\x20\x24\x7b\x63\x6c\x75\x73\x74\x65\x72\x5f\x69\x64\x7d\x20\x2d\x63\x20\x24\x7b\x6b\x61\x66\x6b\x61\x5f\x64\x69\x72\x7d\x2f\x63\x6f\x6e\x66\x69\x67\x2f\x6b\x72\x61\x66\x74\x2f\x24\x7b\x70\x72\x6f\x63\x65\x73\x73\x5f\x72\x6f\x6c\x65\x7d\x2e\x70\x72\x6f\x70\x65\x72\x74\x69\x65\x73\x22\x0a\x0a\x20\x20\x65\x78\x65\x63\x20\x22\x24\x7b\x6b\x61\x66\x6b\x61\x5f\x64\x69\x72\x7d\x2f\x62\x69\x6e\x2f\x6b\x61\x66\x6b\x61\x2d\x73\x65\x72\x76\x65\x72\x2d\x73\x74\x61\x72\x74\x2e\x73\x68\x22\x20\x22\x24\x7b\x6b\x61\x66\x6b\x61\x5f\x64\x69\x72\x7d\x2f\x63\x6f\x6e\x66\x69\x67\x2f\x6b\x72\x61\x66\x74\x2f\x24\x7b\x70\x72\x6f\x63\x65\x73\x73\x5f\x72\x6f\x6c\x65\x7d\x2e\x70\x72\x6f\x70\x65\x72\x74\x69\x65\x73\x22\x0a\x7d\x0a\x0a\x23\x20\x50\x61\x72\x73\x65\x20\x63\x6f\x6d\x6d\x61\x6e\x64\x2d\x6c\x69\x6e\x65\x20\x61\x72\x67\x75\x6d\x65\x6e\x74\x73\x0a\x5b\x5b\x20\x24\x23\x20\x2d\x6c\x74\x20\x31\x20\x5d\x5d\x20\x26\x26\x20\x75\x73\x61\x67\x65\x20\x30\x0a\x23\x20\x44\x69\x73\x70\x6c\x61\x79\x20\x74\x68\x65\x20\x68\x65\x6c\x70\x20\x74\x65\x78\x74\x20\x69\x66\x20\x2d\x68\x20\x6f\x72\x20\x2d\x2d\x68\x65\x6c\x70\x20\x61\x70\x70\x65\x61\x72\x73\x20\x69\x6e\x20\x74\x68\x65\x20\x63\x6f\x6d\x6d\x61\x6e\x64\x20\x6c\x69\x6e\x65\x0a\x66\x6f\x72\x20\x61\x72\x67\x20\x69\x6e\x20\x22\x24\x7b\x40\x7d\x22\x3b\x20\x64\x6f\x0a\x20\x20\x63\x61\x73\x65\x20\x22\x24\x7b\x61\x72\x67\x7d\x22\x20\x69\x6e\x0a\x20\x20\x2d\x68\x20\x7c\x20\x2d\x2d\x68\x65\x6c\x70\x29\x20\x75\x73\x61\x67\x65\x20\x30\x20\x3b\x3b\x0a\x20\x20\x2d\x2d\x29\x20\x62\x72\x65\x61\x6b\x20\x3b\x3b\x0a\x20\x20\x2a\x29\x20\x3b\x3b\x0a\x20\x20\x65\x73\x61\x63\x0a\x64\x6f\x6e\x65\x0a\x61\x63\x74\x69\x6f\x6e\x3d\x22\x24\x7b\x31\x7d\x22\x0a\x73\x68\x69\x66\x74\x0a\x63\x61\x73\x65\x20\x22\x24\x7b\x61\x63\x74\x69\x6f\x6e\x7d\x22\x20\x69\x6e\x0a\x68\x65\x6c\x70\x29\x20\x75\x73\x61\x67\x65\x20\x30\x20\x3b\x3b\x0a\x0a\x75\x70\x29\x0a\x20\x20\x6b\x61\x66\x6b\x61\x5f\x22\x24\x7b\x61\x63\x74\x69\x6f\x6e\x7d\x22\x20\x22\x24\x7b\x40\x7d\x22\x0a\x20\x20\x65\x78\x69\x74\x20\x30\x0a\x20\x20\x3b\x3b\x0a\x0a\x2a\x29\x0a\x20\x20\x65\x63\x68\x6f\x20\x22\x55\x6e\x6b\x6e\x6f\x77\x6e\x20\x63\x6f\x6d\x6d\x61\x6e\x64\x20\x27\x24\x7b\x61\x63\x74\x69\x6f\x6e\x7d\x27\x2e\x20\x20\x54\x79\x70\x65\x20\x27\x24\x7b\x73\x63\x72\x69\x70\x74\x5f\x70\x61\x74\x68\x7d\x20\x2d\x2d\x68\x65\x6c\x70\x27\x20\x66\x6f\x72\x20\x75\x73\x61\x67\x65\x20\x69\x6e\x66\x6f\x72\x6d\x61\x74\x69\x6f\x6e\x2e\x22\x0a\x20\x20\x65\x78\x69\x74\x20\x31\x0a\x20\x20\x3b\x3b\x0a\x65\x73\x61\x63\x0a" + +func defaultsUpShBytes() ([]byte, error) { + return bindataRead( + _defaultsUpSh, + "defaults/up.sh", + ) +} + +func defaultsUpSh() (*asset, error) { + bytes, err := defaultsUpShBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "defaults/up.sh", size: 12019, mode: os.FileMode(420), modTime: time.Unix(1728022046, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +// Asset loads and returns the asset for the given name. +// It returns an error if the asset could not be found or +// could not be loaded. +func Asset(name string) ([]byte, error) { + cannonicalName := strings.Replace(name, "\\", "/", -1) + if f, ok := _bindata[cannonicalName]; ok { + a, err := f() + if err != nil { + return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err) + } + return a.bytes, nil + } + return nil, fmt.Errorf("Asset %s not found", name) +} + +// MustAsset is like Asset but panics when Asset would return an error. +// It simplifies safe initialization of global variables. +func MustAsset(name string) []byte { + a, err := Asset(name) + if err != nil { + panic("asset: Asset(" + name + "): " + err.Error()) + } + + return a +} + +// AssetInfo loads and returns the asset info for the given name. +// It returns an error if the asset could not be found or +// could not be loaded. +func AssetInfo(name string) (os.FileInfo, error) { + cannonicalName := strings.Replace(name, "\\", "/", -1) + if f, ok := _bindata[cannonicalName]; ok { + a, err := f() + if err != nil { + return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err) + } + return a.info, nil + } + return nil, fmt.Errorf("AssetInfo %s not found", name) +} + +// AssetNames returns the names of the assets. +func AssetNames() []string { + names := make([]string, 0, len(_bindata)) + for name := range _bindata { + names = append(names, name) + } + return names +} + +// _bindata is a table, holding each asset generator, mapped to its name. +var _bindata = map[string]func() (*asset, error){ + "defaults/up.sh": defaultsUpSh, +} + +// AssetDir returns the file names below a certain +// directory embedded in the file by go-bindata. +// For example if you run go-bindata on data/... and data contains the +// following hierarchy: +// data/ +// foo.txt +// img/ +// a.png +// b.png +// then AssetDir("data") would return []string{"foo.txt", "img"} +// AssetDir("data/img") would return []string{"a.png", "b.png"} +// AssetDir("foo.txt") and AssetDir("notexist") would return an error +// AssetDir("") will return []string{"data"}. +func AssetDir(name string) ([]string, error) { + node := _bintree + if len(name) != 0 { + cannonicalName := strings.Replace(name, "\\", "/", -1) + pathList := strings.Split(cannonicalName, "/") + for _, p := range pathList { + node = node.Children[p] + if node == nil { + return nil, fmt.Errorf("Asset %s not found", name) + } + } + } + if node.Func != nil { + return nil, fmt.Errorf("Asset %s not found", name) + } + rv := make([]string, 0, len(node.Children)) + for childName := range node.Children { + rv = append(rv, childName) + } + return rv, nil +} + +type bintree struct { + Func func() (*asset, error) + Children map[string]*bintree +} + +var _bintree = &bintree{nil, map[string]*bintree{ + "defaults": &bintree{nil, map[string]*bintree{ + "up.sh": &bintree{defaultsUpSh, map[string]*bintree{}}, + }}, +}} + +// RestoreAsset restores an asset under the given directory +func RestoreAsset(dir, name string) error { + data, err := Asset(name) + if err != nil { + return err + } + info, err := AssetInfo(name) + if err != nil { + return err + } + err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755)) + if err != nil { + return err + } + err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode()) + if err != nil { + return err + } + err = os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime()) + if err != nil { + return err + } + return nil +} + +// RestoreAssets restores an asset under the given directory recursively +func RestoreAssets(dir, name string) error { + children, err := AssetDir(name) + // File + if err != nil { + return RestoreAsset(dir, name) + } + // Dir + for _, child := range children { + err = RestoreAssets(dir, filepath.Join(name, child)) + if err != nil { + return err + } + } + return nil +} + +func _filePath(dir, name string) string { + cannonicalName := strings.Replace(name, "\\", "/", -1) + return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...) +} diff --git a/gen/bindata/main.go b/gen/bindata/main.go new file mode 100644 index 0000000..843961a --- /dev/null +++ b/gen/bindata/main.go @@ -0,0 +1,47 @@ +/* +Copyright 2023 cuisongliu@qq.com. + +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 + + http://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. +*/ + +package main + +import ( + "github.com/cuisongliu/logger" + "github.com/go-bindata/go-bindata" +) + +func main() { + logger.Cfg(true, false) + genBinData() +} + +func genBinData() { + logger.Info("generator bindata start") + bc := &bindata.Config{ + Input: []bindata.InputConfig{ + { + Path: "defaults/up.sh", + }, + }, + Package: "defaults", + NoCompress: true, + NoMemCopy: true, + //NoMetadata: true, + Output: "defaults/zz_generated_bindata.go", + } + if err := bindata.Translate(bc); err != nil { + logger.Fatal(err) + } + logger.Info("generator bindata success") +} diff --git a/gen/gen.go b/gen/version/gen.go similarity index 100% rename from gen/gen.go rename to gen/version/gen.go diff --git a/go.mod b/go.mod index c1bdbe0..529ff37 100644 --- a/go.mod +++ b/go.mod @@ -3,10 +3,13 @@ module github.com/cuisongliu/automq-operator go 1.23 require ( + github.com/cuisongliu/logger v0.0.0-20230412024334-6d0345c427ba + github.com/go-bindata/go-bindata v3.1.2+incompatible github.com/labring/operator-sdk v1.0.5 github.com/onsi/ginkgo/v2 v2.11.0 github.com/onsi/gomega v1.27.10 k8s.io/api v0.28.0 + k8s.io/apiextensions-apiserver v0.28.0 k8s.io/apimachinery v0.28.0 k8s.io/client-go v0.28.0 sigs.k8s.io/controller-runtime v0.16.0 @@ -63,7 +66,6 @@ require ( gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/apiextensions-apiserver v0.28.0 // indirect k8s.io/component-base v0.28.0 // indirect k8s.io/klog/v2 v2.100.1 // indirect k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 // indirect diff --git a/go.sum b/go.sum index e9564d5..b9d9455 100644 --- a/go.sum +++ b/go.sum @@ -93,6 +93,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsr github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/cuisongliu/logger v0.0.0-20230412024334-6d0345c427ba h1:NnI/2qCBNm8EkvL3jK6kAJ5szFTT0oRUDDjdV44SlNU= +github.com/cuisongliu/logger v0.0.0-20230412024334-6d0345c427ba/go.mod h1:w7Phuvu7fo9foe+q8V5LRe4Om/+6x8e1D7utm/WFzKk= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -124,6 +126,8 @@ github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4 github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-bindata/go-bindata v3.1.2+incompatible h1:5vjJMVhowQdPzjE1LdxyFF7YFTXg5IgGVW4gBr5IbvE= +github.com/go-bindata/go-bindata v3.1.2+incompatible/go.mod h1:xK8Dsgwmeed+BBsSy2XTopBn/8uK2HWuGSnA11C3Joo= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=