#!/bin/bash
## -*- encoding: utf-8 -*- vim:tabstop=8:shiftwidth=2
##
## _人人人人人人_
## > 突然の死 < ジェネレーター (Echo "sudden death" message)
##  ̄Y^Y^Y^Y^Y^Y ̄
## Copyright (C) 2013-2022 SATOH Fumiyasu @ OSSTech Corp., Japan
##               <https://github.com/fumiyas/home-commands/blob/master/echo-sd>
##               <https://fumiyas.github.io/>
##               <https://www.osstech.co.jp/cgi-bin/echo-sd>
##
## License: GNU General Public License version 3
##
## Requirements:
##   * bash(1) 4.0, ksh(1) 93u or zsh(1) 4.3
##   * openssl(1) 1.0.2 if you use Twitter
##
## How to install:
##
##   $ mkdir -p $HOME/bin
##   $ cd $HOME/bin
##   $ wget -nv https://raw.githubusercontent.com/fumiyas/home-commands/master/echo-sd
##   $ chmod +x echo-sd
##   $ export PATH="$HOME/bin:$PATH"
##   $ alias echo=echo-sd
##   $ alias banner=echo-sd
##
## Examples for Command-line mode:
##
##   $ echo-sd --help
##   ...
##   $ echo-sd
##   _人人人人人人_
##   > 突然の死 <
##    ̄Y^Y^Y^Y^Y^Y ̄
##   $ echo-sd -t
##   (Tweet message in Twitter)
##   $ echo-sd ぬるぽっ!!
##   _人人人人人人人_
##   > ぬるぽっ!! <
##    ̄Y^Y^Y^Y^Y^Y^Y ̄
##   $ echo-sd -v ガッ!
##   _人人_
##   > ガ <
##   > ッ <
##   > ! <
##    ̄Y^Y ̄
##   $ echo-sd -p1 ズキュウウゥン!!
##     _人人人人人人人人人人_
##    >           <
##   >  ズキュウウゥン!!  <
##    >           <
##      ̄Y^Y^Y^Y^Y^Y^Y^Y^Y^Y ̄
##   $ echo-sd -vp1 ゴゴゴゴゴゴゴゴ 「世界」ッ! 時よ止まれ!
##     _人人人人人_
##    >      <
##   > 時  ┐ ゴ <
##   > よ 世 ゴ <
##   > 止 界 ゴ <
##   > ま └  ゴ <
##   > れ ッ ゴ <
##   > ! ! ゴ <
##   >     ゴ <
##   >     ゴ <
##    >      <
##      ̄Y^Y^Y^Y^Y ̄
##
## Examples for CGI mode:
##
##   $ GATEWAY_INTERFACE=CGI/1.0 QUERY_STRING=s=おっす!\&o=v echo-sd
##   Content-Type: text/html; charset=UTF-8
##   ...
##   <pre>
##   _人人_
##   > お <
##   > っ <
##   > す <
##   > ! <
##    ̄Y^Y ̄
##   </pre><hr>
##   ...
##
## On-line demo site:
##
##   https://www.OSSTech.co.jp/cgi-bin/echo-sd
##
## TODO:
##
##   * --rest (REST IN PEACE)
##   * --center with --vertical
##
## Inspired by:
##
##   * 突然の死ジェネレータ - powered by starwing.net, created by @karno.
##     http://starwing.net/suddenly_death.html
##   * 突然の死ジェネレータ - 純粋関数空間
##     http://tanakh.jp/tools/sudden.html
##   * 元ネタ
##     https://dic.nicovideo.jp/a/%E7%AA%81%E7%84%B6%E3%81%AE%E6%AD%BB
##

if [[ ${0##*/} == echo-sd ]] && [[ ${zsh_eval_context-toplevel} == toplevel ]]; then
  set -u

  case "${BASH_VERSION-}" in
  [1-3].*)
    if type zsh >/dev/null 2>&1; then
      unset BASH_VERSION
      exec zsh "$0" ${1+"$@"}
      exit 1
    fi
    echo "${0##*/}: ERROR: bash 4 or later required" 1>&2
    exit 1
    ;;
  esac
fi

typeset SD_arg0="$0"
typeset SD_copyright='(C) 2013-2022 SATOH Fumiyasu @ OSSTech Corp., Japan'
typeset SD_url='https://github.com/fumiyas/home-commands/blob/master/echo-sd'
typeset SD_lang_orig SD_lang
typeset SD_bc_tl SD_bc_t SD_bc_tr
typeset SD_bc_l SD_bc_r
typeset SD_bc_bl SD_bc_b SD_bc_br
typeset -A SD_vc_map
typeset SD_c_lf='
'

## ======================================================================

function SD_die {
  SD_echo_command "${SD_arg0##*/}: ERROR: $1" 1>&2
  SD_echo_command 1>&2
  exit "${2-1}"
}

function SD_init {
  if [[ -n ${ZSH_VERSION-} ]]; then
    setopt SH_WORD_SPLIT
    setopt BSD_ECHO
    setopt KSH_GLOB
    setopt KSH_ARRAYS
  elif [[ -n ${BASH_VERSION-} ]]; then
    shopt -u xpg_echo
  else ## ksh
    if [[ $(echo -n) == -n ]]; then
      alias echo='print -r'
    fi
  fi

  typeset locale lang_ja lang
  SD_lang_orig="${LANG-}"
  if [[ ${SD_lang_orig#*.} != @(UTF-8|utf-8|UTF8|utf8) ]]; then
    if type locale >/dev/null 2>&1; then
      while read -r locale; do
	if [[ ${locale#*.} == @(UTF-8|utf-8|UTF8|utf8) ]]; then
	  if [[ ${locale%.*} == ja_JP ]]; then
	    lang_ja="$locale"
	  else
	    lang="$locale"
	  fi
	fi
      done < <(locale -a)
    fi
  fi
  SD_lang="${lang_ja-${lang-ja_JP.UTF-8}}"

  SD_bc_tl="_"
  SD_bc_t="人"
  SD_bc_tr="_"
  SD_bc_l=">"
  SD_bc_r="<"
  SD_bc_bl=" ̄"
  SD_bc_b="Y^"
  SD_bc_br=" ̄"

  if [[ -n ${ZSH_VERSION-} ]]; then
    SD_vc_map=()
  else
    SD_vc_map=
  fi
  SD_vc_map[↑]=' → '
  SD_vc_map[↓]=' ← '
  SD_vc_map[←]=' ↑ '
  SD_vc_map[→]=' ↓ '
  SD_vc_map[。]=' ︒ '
  SD_vc_map[、]=' ︑ '
  SD_vc_map[ー]=' | '
  SD_vc_map[─]=' | '
  SD_vc_map[−]=' | '
  SD_vc_map[-]=' | '
  SD_vc_map[〜]=' ∫ '
  SD_vc_map[~]=' ∫ '
  SD_vc_map[/]=' \ '
  SD_vc_map[…]=' ︙ '
  SD_vc_map[‥]=' ︰ '
  SD_vc_map[︙]=' … '
  SD_vc_map[:]=' ‥ '
  SD_vc_map[:]=' ‥ '
  SD_vc_map[=]=' ॥ '
  SD_vc_map[=]=' ॥ '
  SD_vc_map[(]=' ⏜ '
  SD_vc_map[\(]=' ⏜ '
  SD_vc_map[)]=' ⏝ '
  SD_vc_map[\)]=' ⏝ '
  SD_vc_map[[]=' ⎴  '
  SD_vc_map[\[]=' ⎴ '
  SD_vc_map[]]=' ⎵ '
  SD_vc_map[\]]=' ⎵ '
  SD_vc_map[{]=' ⏞ '
  SD_vc_map[\{]=' ⏞ '
  SD_vc_map[<]=' ∧ '
  SD_vc_map[\<]=' ∧ '
  SD_vc_map[>]=' ∨ '
  SD_vc_map[\>]=' ∨ '
  SD_vc_map[}]=' ⏟ '
  SD_vc_map[\}]=' ⏟ '
  SD_vc_map[「]='  ┐'
  SD_vc_map[」]='└  '
  SD_vc_map[【]=' ︗ '
  SD_vc_map[】]=' ︘ '
  SD_vc_map[〖]=' ︗ '
  SD_vc_map[〗]=' ︘ '
  SD_vc_map[「]='  ┐'
  SD_vc_map[」]='└  '
  SD_vc_map[-]=' |  '
  SD_vc_map[ー]=' |  '
  SD_vc_map[,]="  ' "
  SD_vc_map[、]='  ` '
}

function _SD_fill_string_by_char {
  typeset str char
  str="$1"; shift
  char="$1"; shift

  ## Why bash on ja_JP.UTF-8 locale matches '[¥]' with '︙' (and others?)
  #str="${str//[ -~。-゚¢£¥¦¬¯]/$char}"
  str="${str//[ -~。-゚¢£¦¬¯]/$char}"
  str="${str//¥/$char}"
  str="${str//[! ]/$char$char}"

  echo "$str"
}

function _SD_pad_space {
  printf "%${1}s" ''
}

function _SD_string_width {
  typeset str
  str=$(_SD_fill_string_by_char "$1" ' ')

  echo "${#str}"
}

function _SD_echo_with_padding {
  typeset str width
  str="$1"; shift
  width="$1"; shift

  echo "${str}$(_SD_pad_space "$((width-$(_SD_string_width "${1-$str}")))")"
}

function SD_echo_header {
  typeset opt
  typeset round="set"
  typeset bc_t="$SD_bc_t" bc_tl="$SD_bc_tl" bc_tr="$SD_bc_tr" bc_tc=""
  typeset bc_l="$SD_bc_l" bc_r="$SD_bc_r"

  while [[ $# -gt 0 ]]; do
    opt="$1"; shift

    case "$opt" in
    --no-round)
      round=""
      ;;
    --bc-[tlr]|--bc-t[clr])
      if [[ ! -n ${1+set} ]]; then
	SD_die "Option value required: $opt"
      fi
      eval "bc_${opt##*-}=\"\$1\""
      shift
      ;;
    --)
      break
      ;;
    -*)
      SD_die "Invalid option: $opt"
      ;;
    *)
      set -- "$opt" ${1+"$@"}
      break
      ;;
    esac
  done

  typeset width="$1"; shift
  typeset padding="$1"; shift
  typeset template left=
  typeset -a paddings=()

  if [[ -n ${round-} && $width -ge 2 && $padding -gt 0 ]]; then
    left=" "
    let width--
  else
    left=""
  fi
  template=$(_SD_pad_space "$width")
  while [[ $padding -gt 0 ]]; do
    if [[ -n ${round-} ]] && [[ $width -ge 2 ]]; then
      template="${template#?}"
      let width--
    fi

    paddings=(
      "$left$bc_l ${template//  / } $bc_r"
      ${paddings[@]+"${paddings[@]}"}
    )

    if [[ -n ${round-} ]] && [[ $width -ge 2 ]]; then
      template="${template#?}"
      left="$left "
      let width--
    fi
    let padding--
  done

  typeset top
  if [[ -n $bc_tc ]]; then
    width=$(_SD_string_width "$template")
    template="$(_SD_pad_space $((width / 2)))"
    top="${template//  /$bc_t}$bc_tc${template//  /$bc_t}"
  else
    template+="    "
    top="${template//  /$bc_t}"
  fi
  echo "${left//  / }$bc_tl${top// /}$bc_tr"

  for padding_s in ${paddings[@]+"${paddings[@]}"}; do
    echo "${padding_s//  / }"
  done
}

function SD_echo_footer {
  typeset opt
  typeset round="set"
  typeset bc_b="$SD_bc_b" bc_bl="$SD_bc_bl" bc_br="$SD_bc_br"
  typeset bc_l="$SD_bc_l" bc_r="$SD_bc_r"

  while [[ $# -gt 0 ]]; do
    opt="$1"; shift

    case "$opt" in
    --no-round)
      round=""
      ;;
    --bc-[blr]|--bc-b[lr])
      if [[ ! -n ${1+set} ]]; then
	SD_die "Option value required: $opt"
      fi
      eval "bc_${opt##*-}=\"\$1\""
      shift
      ;;
    --)
      break
      ;;
    -*)
      SD_die "Invalid option: $opt"
      ;;
    *)
      set -- "$opt" ${1+"$@"}
      break
      ;;
    esac
  done

  typeset width="$1"; shift
  typeset padding="$1"; shift
  typeset template left=

  if [[ -n ${round-} && $width -ge 2 && $padding -gt 0 ]]; then
    left=" "
    let width--
  fi
  template=$(_SD_pad_space "$width")
  while [[ $padding -gt 0 ]]; do
    if [[ -n ${round-} ]] && [[ $width -ge 2 ]]; then
      template="${template#?}"
      let width--
    fi

    echo "${left//  / }$bc_l ${template//  / } $bc_r"

    if [[ -n ${round-} ]] && [[ $width -ge 2 ]]; then
      template="${template#?}"
      left="$left "
    fi
    let padding--
  done

  template+="    " ## FIXME: Support --bc-bc
  typeset bottom
  bottom="${template//  /$bc_b}"
  echo "${left//  / }$bc_bl${bottom// /}$bc_br"
}

function SD_echo_horizontal {
  typeset opt
  typeset round
  typeset bc_tl bc_t bc_tr bc_l bc_r bc_bl bc_b bc_br
  typeset padding_top=0 padding_bottom=0 padding_left=0 padding_right=0
  typeset center

  while [[ $# -gt 0 ]]; do
    opt="$1"; shift

    case "$opt" in
    --no-round)
      no_round="set"
      ;;
    --bc-[tblr]|--bc-t[lr]|--bc-b[lr])
      if [[ ! -n ${1+set} ]]; then
	SD_die "Option value required: $opt"
      fi
      eval "bc_${opt##*-}=\"\$1\""
      shift
      ;;
    --padding)
      if [[ ${1-BAD} == @(*[!0-9]*) ]]; then
	SD_die "Invalid option value: $opt ${1-UNSPECIFIED}"
      fi
      padding_top="$((($1 + 1) / 2))"
      padding_bottom="$padding_top"
      padding_left="$1"
      padding_right="$1"
      shift
      ;;
    --padding-top|--padding-bottom|--padding-left|--padding-right)
      if [[ ${1-BAD} == @(*[!0-9]*) ]]; then
	SD_die "Invalid option value: $opt ${1-UNSPECIFIED}"
      fi
      case "$opt" in
      --padding-top)
	padding_top="$1"
	;;
      --padding-bottom)
	padding_bottom="$1"
	;;
      --padding-left)
	padding_left="$1"
	;;
      --padding-right)
	padding_right="$1"
	;;
      esac
      shift
      ;;
    --center)
      center="set"
      ;;
    --)
      break
      ;;
    -*)
      SD_die "Invalid option: $opt"
      ;;
    *)
      set -- "$opt" ${1+"$@"}
      break
      ;;
    esac
  done

  export LANG="$SD_lang"

  typeset -a scripts=()
  typeset script width width_tmp
  typeset padding_left_s padding_right_s
  width=0
  padding_left_s=$(_SD_pad_space "$padding_left")
  padding_right_s=$(_SD_pad_space "$padding_right")
  for script in ${1+"$@"}; do
    script="$padding_left_s$script$padding_right_s"
    scripts+=("$script")
    width_tmp=$(_SD_string_width "$script")
    if [[ $width_tmp -gt $width ]]; then
      width="$width_tmp"
    fi
  done
  if [[ -n ${center-} && $((width % 2)) -eq 1 ]]; then
    let width++
  fi

  SD_echo_header \
    ${no_round:+--no-round} \
    --bc-tl "${bc_tl:-$SD_bc_tl}" \
    --bc-t  "${bc_t:-$SD_bc_t}" \
    --bc-tr "${bc_tr:-$SD_bc_tr}" \
    --bc-l  "${bc_l:-$SD_bc_l}" \
    --bc-r  "${bc_r:-$SD_bc_r}" \
    "$width" \
    "$padding_top" \
    ;

  typeset line
  for script in ${scripts[@]+"${scripts[@]}"}; do
    if [[ -n ${center-} ]]; then
      typeset padding=$(((width - $(_SD_string_width "$script")) / 2))
      if [[ $padding -gt 0 ]]; then
	script="$(_SD_pad_space "$padding")$script"
      fi
    fi
    line="${bc_l:-$SD_bc_l} $(_SD_echo_with_padding "${script}" "$width") ${bc_r:-$SD_bc_r}"
    echo "${line//  / }"
  done

  SD_echo_footer \
    ${no_round:+--no-round} \
    --bc-bl "${bc_bl:-$SD_bc_bl}" \
    --bc-b  "${bc_b:-$SD_bc_b}" \
    --bc-br "${bc_br:-$SD_bc_br}" \
    --bc-l  "${bc_l:-$SD_bc_l}" \
    --bc-r  "${bc_r:-$SD_bc_r}" \
    "$width" \
    "$padding_bottom" \
    ;

  export LANG="$SD_lang_orig"
}

function SD_echo_vertical {
  typeset opt
  typeset no_round
  typeset bc_tc bc_tl bc_t bc_tr bc_l bc_r bc_bl bc_b bc_br
  typeset padding_top=0 padding_bottom=0 padding_left=0 padding_right=0
  typeset center
  typeset tanzaku

  while [[ $# -gt 0 ]]; do
    opt="$1"; shift

    case "$opt" in
    --no-round)
      no_round="set"
      ;;
    --bc-[tblr]|--bc-t[clr]|--bc-b[lr])
      if [[ ! -n ${1+set} ]]; then
	SD_die "Option value required: $opt"
      fi
      eval "bc_${opt##*-}=\"\$1\""
      shift
      ;;
    --padding)
      if [[ ${1-BAD} == @(*[!0-9]*) ]]; then
	SD_die "Invalid option value: $opt ${1-UNSPECIFIED}"
      fi
      padding_top="$((($1 + 1) / 2))"
      padding_bottom="$padding_top"
      padding_left="$1"
      padding_right="$1"
      shift
      ;;
    --padding-top|--padding-bottom|--padding-left|--padding-right)
      if [[ ${1-BAD} == @(*[!0-9]*) ]]; then
	SD_die "Invalid option value: $opt ${1-UNSPECIFIED}"
      fi
      case "$opt" in
      --padding-top)
	padding_top="$1"
	;;
      --padding-bottom)
	padding_bottom="$1"
	;;
      --padding-left)
	padding_left="$1"
	;;
      --padding-right)
	padding_right="$1"
	;;
      esac
      shift
      ;;
    --center)
      center="set"
      ;;
    --tanzaku)
      tanzaku="set"
      ;;
    --)
      break
      ;;
    -*)
      SD_die "Invalid option: $opt"
      ;;
    *)
      set -- "$opt" ${1+"$@"}
      break
      ;;
    esac
  done

  export LANG="$SD_lang"

  ## FIXME: Implement --center option

  typeset -a lines=()
  typeset line line_n
  typeset script script_n trailer trailer2 letter letter_width next
  letter_width=4
  script_n=0
  for script in ${1+"$@"}; do
    line_n=0
    trailer="$script"

    while [[ -n $script ]]; do
      trailer="${trailer#?}"
      letter="${script%$trailer}"
      script="${script#?}"
      if [[ -n ${SD_vc_map[$letter]-} ]]; then
	line="${SD_vc_map[$letter]}"
      else
	trailer2="${trailer#?}"
	next="${script%$trailer2}"
	if [[ $next == @(゙|゚) ]] || [[ $letter$next == @([\?!][\?!]) ]]; then
	  line=" $letter$next "
	  trailer="$trailer2"
	  script="${script#?}"
	else
	  line=" ${letter} "
	fi
      fi

      if [[ -z ${lines[$line_n]-} ]]; then
	lines[$line_n]="$(_SD_pad_space $((script_n * letter_width)))"
      fi
      lines[$line_n]="$(_SD_echo_with_padding "${line}" $letter_width)${lines[$line_n]}"
      let line_n+=1
    done

    while [[ $line_n -lt ${#lines[@]} ]]; do
      lines[$line_n]="$(_SD_pad_space $letter_width)${lines[$line_n]}"
      let line_n+=1
    done

    let script_n+=1
  done

  typeset line_width=$(((script_n - 1) * letter_width))
  let line_width+=$padding_left+$padding_right

  typeset padding_left_s padding_right_s
  padding_left_s=$(_SD_pad_space "$padding_left")
  padding_right_s=$(_SD_pad_space "$padding_right")

  SD_echo_header \
    ${no_round:+--no-round} \
    ${bc_tc:+--bc-tc "$bc_tc"} \
    --bc-tl "${bc_tl:-$SD_bc_tl}" \
    --bc-t  "${bc_t:-$SD_bc_t}" \
    --bc-tr "${bc_tr:-$SD_bc_tr}" \
    --bc-l  "${bc_l:-$SD_bc_l}" \
    --bc-r  "${bc_r:-$SD_bc_r}" \
    "$line_width" \
    "$padding_top" \
    ;

  for line in ${lines[@]+"${lines[@]}"}; do
    line="$padding_left_s$line$padding_right_s"
    echo "${bc_l:-$SD_bc_l}${line//  / }${bc_r:-$SD_bc_r}"
  done

  SD_echo_footer \
    ${no_round:+--no-round} \
    --bc-bl "${bc_bl:-$SD_bc_bl}" \
    --bc-b  "${bc_b:-$SD_bc_b}" \
    --bc-br "${bc_br:-$SD_bc_br}" \
    --bc-l  "${bc_l:-$SD_bc_l}" \
    --bc-r  "${bc_r:-$SD_bc_r}" \
    "$line_width" \
    "$padding_bottom" \
    ;

  export LANG="$SD_lang_orig"
}

function SD_echo_command_help {
  {
    SD_bc_r="< ジェネレーター" SD_echo_command
    cat <<EOT
Usage: ${SD_arg0##*/} [OPTIONS] [SCRIPT ...]

Options:
 --help
    Print this message
 -v, --vertical
    Print scripts vertically
 -t, --tweet
    Tweet in Twitter
 -h, --header HEADER
 -f, --footer FOOTER
    Header and footer script(s)
 -s, --read-stdin
    Read scripts from stdin
 --stress
    "Stress" mode
 --stream
    Stream mode
 -b, --border-char CHARACTER
    Border character
 --tanzaku
    "Tanzaku" border
 --center
    Center scripts (not implemented in vertical mode yet)
 -R, --no-round
    Do not round border
 --square
    Square border
 -p, --padding SIZE
 --pt, --padding-top SIZE
 --pb, --padding-bottom SIZE
 --pl, --padding-left SIZE
 --pr, --padding-right SIZE
    Padding size
EOT
  } |SD_echo_command --read-stdin
}

function SD_echo_command {
  typeset opt
  typeset read_stdin vertical stress stream
  typeset no_round square tanzaku border_char
  typeset padding padding_top padding_bottom padding_left padding_right
  typeset center
  typeset header= footer=
  typeset tweet

  while [[ $# -gt 0 ]]; do
    opt="$1"; shift

    ## -ovalue → -o value
    if [[ -z "${opt##-[bphf]?*}" ]]; then
      set -- "${opt#??}" ${1+"$@"}
      opt="${opt%$1}"
    ## -abc → -a -bc
    elif [[ -z "${opt##-[!-]?*}" ]]; then
      set -- "-${opt#??}" ${1+"$@"}
      opt="${opt%${1#-}}"
    ## --option=value → --option value
    elif [[ -z "${opt##--*=*}" ]]; then
      set -- "${opt#--*=}" ${1+"$@"}
      opt="${opt%%=*}"
    fi

    case "$opt" in
    --help)
      SD_echo_command_help
      exit 0
      ;;
    -s|--read-stdin)
      read_stdin="set"
      stream=""
      ;;
    -v|--vertical)
      vertical="set"
      ;;
    --stress)
      stress="set"
      ;;
    --stream)
      stream="set"
      read_stdin=""
      ;;
    -R|--no-round)
      no_round="set"
      ;;
    -p|--padding)
      if [[ ${1-BAD} == @(*[!0-9]*) ]]; then
	SD_die "Invalid option value: $opt ${1-UNSPECIFIED}"
      fi
      padding="$1"
      shift
      ;;
    --p[tblr]|--padding-top|--padding-bottom|--padding-left|--padding-right)
      if [[ ${1-BAD} == @(*[!0-9]*) ]]; then
	SD_die "Invalid option value: $opt ${1-UNSPECIFIED}"
      fi
      case "$opt" in
      --pt|--padding-top)
	padding_top="$1"
	;;
      --pb|--padding-bottom)
	padding_bottom="$1"
	;;
      --pl|--padding-left)
	padding_left="$1"
	;;
      --pr|--padding-right)
	padding_right="$1"
	;;
      esac
      shift
      ;;
    -b|--bc|--border-char|--border-character)
      if [[ -z ${1-} ]]; then
	SD_die "Invalid option value: $opt ${1-UNSPECIFIED}"
      fi
      border_char="$1"
      shift
      ;;
    --square)
      square="set"
      no_round="set"
      ;;
    --tanzaku)
      tanzaku="set"
      vertical="set"
      no_round="set"
      ;;
    --center)
      center="set"
      ;;
    -h|--header)
      if [[ -z ${1-} ]]; then
	SD_die "Invalid option value: $opt ${1-UNSPECIFIED}"
      fi
      header+="$1"
      shift
      ;;
    -f|--footer)
      if [[ -z ${1-} ]]; then
	SD_die "Invalid option value: $opt ${1-UNSPECIFIED}"
      fi
      footer+="$1"
      shift
      ;;
    -t|--tweet)
      tweet="set"
      ;;
    --)
      break
      ;;
    -*)
      SD_die "Invalid option: $opt"
      ;;
    *)
      set -- "$opt" ${1+"$@"}
      break
      ;;
    esac
  done

  typeset -a sd_opts=(
    ${no_round:+--no-round}
    ${center:+--center}
    ${padding:+--padding "$padding"}
    ${padding_top:+--padding-top "$padding_top"}
    ${padding_bottom:+--padding-bottom "$padding_bottom"}
    ${padding_left:+--padding-left "$padding_left"}
    ${padding_right:+--padding-right "$padding_right"}
  )
  if [[ -n ${border_char-} ]]; then
    sd_opts+=(
      --bc-tl "$border_char" --bc-t "$border_char" --bc-tr "$border_char"
      --bc-l  "$border_char" --bc-r "$border_char"
      --bc-bl "$border_char" --bc-b "$border_char" --bc-br "$border_char"
    )
  elif [[ -n ${square-} ]]; then
    sd_opts+=(
      --bc-tl '┌' --bc-t '─' --bc-tr '┐'
      --bc-l '│' --bc-r '│'
      --bc-bl '└' --bc-b '─' --bc-br '┘'
    )
  elif [[ -n ${tanzaku-} ]]; then
    sd_opts+=(
      --bc-tc '-┷-'
      --bc-tl '┏' --bc-t '━' --bc-tr '┓'
      --bc-l '┃' --bc-r '┃'
      --bc-bl '┗' --bc-b '━' --bc-br '┛'
    )
  fi

  header="$(echo -e "$header")${header:+$SD_c_lf}"
  footer="$(echo -e "$footer")"

  if [[ -n ${stress-} ]]; then
    header+="${1-仕事のストレス}$SD_c_lf"; ${1+shift}
    header+="    ↘$SD_c_lf"
    header+="   ${1-仕事のストレス}$SD_c_lf"; ${1+shift}
    header+="    ↙$SD_c_lf"
    header+="${1-仕事のストレス}$SD_c_lf"; ${1+shift}
    header+="    ↘$SD_c_lf"
    header+="   ${1-仕事のストレス}$SD_c_lf"; ${1+shift}
    header+="    ↙$SD_c_lf"
  fi

  if [[ -n ${read_stdin-} ]]; then
    while IFS= read -r line; do
      set -- ${1+"$@"} "$line"
    done
  fi

  if [[ -z ${stream-} ]]; then
    if [[ $# -eq 0 ]]; then
      if [[ -n ${stress-} ]]; then
	set -- '仕事のストレス'
      else
	set -- '突然の死'
      fi
    fi

    typeset sd="$header"
    if [[ -z ${vertical-} ]]; then
      sd+=$(SD_echo_horizontal ${sd_opts[@]+"${sd_opts[@]}"} -- ${1+"$@"})
    else
      sd+=$(SD_echo_vertical ${sd_opts[@]+"${sd_opts[@]}"} -- ${1+"$@"})
    fi
    sd+="${footer:+$SD_c_lf$footer}"

    if [[ -n ${tweet-} ]]; then
      if [[ $sd = @( *) ]]; then
	sd=".${sd# }"
      elif [[ $sd = @( *) ]]; then
	sd=".${sd# }"
      fi
      Tweet_init
      Tweet_command "$sd"
    else
      echo "$sd"
    fi
  else
    echo -n "$header"
    while :; do
      IFS= read -r line || break
      set -- ${1+"$@"} "$line"

      if [[ -z ${vertical-} ]]; then
	SD_echo_horizontal ${sd_opts[@]+"${sd_opts[@]}"} -- ${1+"$@"}
      else
	SD_echo_vertical ${sd_opts[@]+"${sd_opts[@]}"} -- ${1+"$@"}
      fi
      shift $#
    done
    echo "$footer"
  fi
}

function _SD_escape_html {
  if [[ -n ${1+set} ]]; then
    echo "$1"
  else
    cat
  fi \
  |sed \
    -e 's/&/\&amp;/g;' \
    -e 's/</\&lt;/g;' \
    -e 's/>/\&gt;/g;' \
  ;
}

function _SD_urlencode {
  ## FIXME: Unsafe?
  if [[ -n ${1+set} ]]; then
    echo "$1"
  else
    cat
  fi \
  |sed \
    -e 's/%/%25/g;' \
    -e 's/ /%20/g;' \
    -e 's/#/%23/g;' \
    -e 's/&/%26/g;' \
    -e 's/+/%2B/g;' \
    -e 's/;/%3B/g;' \
    -e 's/=/%3D/g;' \
    -e 's/?/%3F/g;' \
    -e 's/\\/%5C/g;' \
    -e 's/\^/%5E/g;' \
    -e 's/{/%7B/g;' \
    -e 's/|/%7C/g;' \
    -e 's/}/%7D/g;' \
    -e 's/~/%7E/g;' \
  ;
}

function _SD_urldecode {
  ## FIXME: Support ksh
  echo -e "$(echo "$1" |sed 's/+/ /g;s/%\(..\)/\\x\1/g;')"
}

function SD_echo_cgi {
  typeset query="${QUERY_STRING-}"
  typeset param value
  typeset tweet text vertical padding square
  typeset -a prefaces=()
  typeset -a scripts=()

  while [[ -n $query ]]; do
    param="${query%%&*}"
    ## '\' is workaround for zsh 4.3.x bug that causes "* not found" error
    name="$(_SD_urldecode "${param%%\=*}")"
    value="$(_SD_urldecode "${param#*=}")"

    case "$name" in
    o|options)
      case "$value" in
      text)
	text="checked"
	;;
      v|vertical)
	vertical="checked"
	;;
      p|padding)
	padding="checked"
	;;
      square)
	square="checked"
	;;
      tanzaku)
	tanzaku="checked"
	padding=""
	;;
      stress)
	stress="checked"
	;;
      esac
      ;;
    p|prefaces)
      while IFS= read -r line; do
	prefaces+=("${line%
}")
      done < <(echo "$value")
      ;;
    s|scripts)
      while IFS= read -r line; do
	scripts+=("${line%
}")
      done < <(echo "$value")
      ;;
    tweet)
      tweet="set"
      ;;
    esac

    if [[ -n ${query##*&*} ]]; then
      break
    fi
    query="${query#*&}"
  done

  set -- \
    ${vertical:+--vertical} \
    ${padding:+--padding 1} \
    ${square:+--square} \
    ${tanzaku:+--tanzaku} \
    ${stress:+--stress} \
    ;
  if [[ ${#scripts[@]} -eq 1 ]] && [[ -z ${scripts[0]} ]]; then
    set -- ${1+"$@"} -- '突然の死'
  else
    set -- ${1+"$@"} -- ${scripts[@]+"${scripts[@]}"}
  fi

  if [[ -n ${tweet-} ]]; then
    echo -n 'Location: https://twitter.com/intent/tweet?text='
    SD_echo_command "$@" \
    |while IFS= read -r line; do
      echo -n "$line" |_SD_urlencode
      echo -n '%0A'
    done
    echo -n "${SD_CGI_FOOTER_TWEET-https://t.co/lNiygmWCSn}" |_SD_urlencode
    echo
    echo
  elif [[ -n ${text-} ]]; then
    echo 'Content-Type: text/plain; charset=UTF-8'
    echo
    for preface in ${prefaces[@]+"${prefaces[@]}"}; do
      echo "$preface"
    done
    SD_echo_command "$@"
  else
    echo 'Content-Type: text/html; charset=UTF-8'
    echo
    echo \
      '<html>' \
      '<head><title>> 突然の死 < ジェネレーター</title></head>' \
      '<style type="text/css"><!--' \
      '.ul { text-decoration:underline; }' \
      '--></style>' \
      '<body><h1>> 突然の死 < ジェネレーター</h1>' \
      '<form action="./echo-sd" method="GET">' \
      ;
    echo -n '<textarea name="scripts" cols="80" rows="4" tabindex="1">'
    for script in ${scripts[@]+"${scripts[@]}"}; do
      _SD_escape_html "$script"
    done
    echo '</textarea><br />'
    echo '<label>' \
      '<input type="checkbox" name="options" value="vertical" accesskey="v" ' \
      "${vertical-}>縦書き(<span class='ul'>V</span>)</label>"
    echo '<label>' \
      '<input type="checkbox" name="options" value="padding" accesskey="p" ' \
      "${padding-}>余白(<span class='ul'>P</span>)</label>"
    echo '<label>' \
      '<input type="checkbox" name="options" value="text" accesskey="r" ' \
      ">テキスト形式(<span class='ul'>R</span>)</label>"
    echo '<br />'
    echo '<label>' \
      '<input type="radio" name="options" value="" accesskey="n" ' \
      "${square-}>通常(<span class='ul'>N</span>)</label>"
    echo '<label>' \
      '<input type="radio" name="options" value="square" accesskey="4" ' \
      "${square-}>四角形(<span class='ul'>4</span>)</label>"
    echo '<label>' \
      '<input type="radio" name="options" value="tanzaku" accesskey="t" ' \
      "${tanzaku-}>短冊(<span class='ul'>T</span>)</label>"
    echo '<label>' \
      '<input type="radio" name="options" value="stress" accesskey="s" ' \
      "${stress-}>ストレス(<span class='ul'>S</span>)</label>"
    echo '<br />'
    echo '<input type="submit" name="generate" value="> ジェネレート <" tabindex="2">'
    echo '<input type="submit" name="tweet" value="> ツイート <" tabindex="2">'
    echo '<br />'
    echo '</form>'
    echo '<!--'
    echo "[$(_SD_escape_html "$*")]"
    echo '-->'
    echo '<pre>'
    for preface in ${prefaces[@]+"${prefaces[@]}"}; do
      _SD_escape_html "$preface"
    done
    SD_echo_command "$@" |_SD_escape_html
    echo '</pre><hr>'
    _SD_escape_html "$SD_copyright"
    echo '<br />'
    echo "<a href='$(_SD_escape_html "$SD_url")'>$(_SD_escape_html "$SD_url")</a>"
    echo '<br>'
    echo "${SD_CGI_FOOTER_HTML-}"
    echo '</body></html>'
  fi
}

## ======================================================================

: ${HOME="/nonexistent"}

TWEET_CONF="${ECHO_SD_CONF-$HOME/.echo-sd.conf}"
TWEET_OAUTH_CONSUMER_KEY="${ECHO_SD_OAUTH_CONSUMER_KEY-qMAuBmchzlryuQahRlnAeg}"
TWEET_OAUTH_CONSUMER_SECRET="${ECHO_SD_OAUTH_CONSUMER_SECRET-JNSzHebO5N5h5nOcYFc1IILP8tqGP4fy28vCBBDFCA}"

## Import tweet.sh from https://github.com/fumiyas/Tweet.sh

typeset Tweet_arg0="$0"
typeset Tweet_lang=''
typeset Tweet_conf_file="${TWEET_CONF-$HOME/.tweet.conf}"
typeset Tweet_api_host="api.twitter.com"
typeset Tweet_api_url="https://$Tweet_api_host/1.1"
typeset Tweet_api_url_request_token="https://$Tweet_api_host/oauth/request_token"
typeset Tweet_api_url_authorize_token="https://$Tweet_api_host/oauth/authorize"
typeset Tweet_api_url_access_token="https://$Tweet_api_host/oauth/access_token"
typeset Tweet_oauth_consumer_key="${TWEET_OAUTH_CONSUMER_KEY-C7IpNPso1IYdCweXYaJ0Q}"
typeset Tweet_oauth_consumer_secret="${TWEET_OAUTH_CONSUMER_SECRET-LAsLscqNC4kBaDW8EtmxMIVCkY8nsw07NaN5PNBYuY}"
typeset Tweet_oauth_access_token=''
typeset Tweet_oauth_access_token_secret=''
typeset Tweet_script_limit='140'
typeset Tweet_c_lf='
'

function Tweet_error {
  echo "${Tweet_arg0##*/}: ERROR: $1" 1>&2
}

function HTTP_browser {
  typeset url="$1"; shift
  typeset open=

  case $(uname) in
  Darwin)
    open="open"
    ;;
  CYGWIN_*)
    open="cygstart"
    ;;
  *)
    if [[ -f /etc/debian_version ]]; then
      open="sensible-browser"
    elif type xdg-open >/dev/null 2>&1; then
      open="xdg-open"
    elif [[ ${XDG_CURRENT_DESKTOP-} == GNOME || -n ${GNOME_DESKTOP_SESSION_ID-} ]] ; then
      open="gnome-open"
    elif [[ ${XDG_CURRENT_DESKTOP-} == KDE || ${KDE_FULL_SESSION-} == true ]] ; then
      open="kde-open"
    else
      typeset browsers="${BROWSER-}"
      if [[ -z $browsers ]]; then
	browsers="www-browser:links2:elinks:links:lynx:w3m"
	if [[ -n ${DISPLAY-} ]]; then
	  browsers="x-www-browser:firefox:seamonkey:mozilla:epiphany:konqueror:chromium:chromium-browser:google-chrome:$browsers"
	fi
      fi

      typeset ifs_save="$IFS"
      typeset found=
      IFS=:
      for open in $browsers; do
	if type "$open" >/dev/null 2>&1; then
	  found=set
	  break
	fi
      done
      IFS="$ifs_save"

      if [[ -z $found ]]; then
	## FIXME: Print error message
	return 1
      fi
    fi
    ;;
  esac

  "$open" "$url"

  return $?
}

function HTTP_pencode {
  if [[ -n ${1+set} ]]; then
    typeset in="${1-}"; shift
  else
    typeset in
    IFS= read -r in
  fi

  typeset LC_ALL='C'
  typeset out=
  typeset char
  while [[ -n "$in" ]]; do
    char="${in:0:1}"
    case "$char" in
    [a-zA-Z0-9\-._~])
      out+="$char"
      ;;
    *)
      out+=$(printf '%%%02X' "'$char")
      ;;
    esac
    in="${in:1}"
  done

  echo -n "$out"
}

function HTTP_pdecode {
  typeset in="${1//\\/\\\\}"; shift

  printf "${in//\%/\\x}"
}

function HTTPS_request {
  typeset url="$1"; shift
  typeset method="$1"; shift

  typeset url_tmp
  #typeset url_scheme="${url%%://*}"
  url_tmp="${url#*://}"
  typeset url_path="/${url_tmp#*/}"
  url_tmp="${url_tmp%%/*}"
  typeset url_host="${url_tmp%%:*}"
  if [[ $url_tmp == @(*:*) ]]; then
    typeset url_port="${url_tmp#*:}"
  else
    typeset url_port='443'
  fi

  typeset line
  typeset -l line_lower
  typeset cert_verify_error= http_ver= rcode= rmessage= content_type= body=

  {
    while IFS= read -r line; do
      line="${line%
}"
      if [[ $line == HTTP/* ]]; then
	http_ver="${line%% *}"
	line="${line#* }"
	rcode="${line%% *}"
	rmessage="${line#* }"
	break
      fi
      if [[ $line == 'verify error':* ]]; then
	cert_verify_error="$line"
      fi
    done

    while IFS= read -r line; do
      line="${line%
}"
      [[ -z $line ]] && break
      line_lower="$line"
      case "$line_lower" in
      content-type:*)
	content_type="${line#*: }"
	;;
      esac
    done
    while IFS= read -r line; do
      line="${line%
}"
      body+="$line$Tweet_c_lf"
    done
    body+="$line"
  } < <(
    {
      echo "$method $url_path HTTP/1.1"
      echo "Host: $url_host"
      echo "Connection: close"
      if [[ $method == 'POST' ]]; then
	echo 'Content-Type: application/x-www-form-urlencoded'
      fi
      while [[ $# -gt 0 ]]; do
	[[ $1 == '--' ]] && { shift; break; }
	echo "$1"
	shift
      done
      typeset query="${1-}"
      typeset LC_ALL='C'
      echo "Content-Length: ${#query}"
      echo
      echo -n "$query"
    } \
    |openssl s_client \
      -connect "$url_host:$url_port" \
      -servername "$url_host" \
      -verify_hostname "$url_host" \
      -no_tls1 \
      -no_ssl3 \
      -crlf \
      -quiet \
      2>&1 \
    ;
  )

  typeset rc='0'

  if [[ -n $cert_verify_error ]]; then
    rcode='500'
    rmessage="Invalid server certificate: $cert_verify_error"
    rc='1'
  elif [[ $rcode != 200 ]]; then
    rc='1'
  fi

  echo "$rcode $rmessage"
  echo "$content_type"
  echo
  echo -n "$body"

  return "$rc"
}

function HTTP_response_extract {
  typeset response="$1"; shift
  typeset name="$1"; shift
  typeset value=

  value="${response#*\&$name=}"
  value="${value#$name=}"
  if [[ $value == "$response" ]]; then
    return 1
  fi
  value="${value%%\&*}"

  echo -n "$value"
  return 0
}

function OAuth_nonce {
  printf '%04x%04x%04x%04x%04x%04x%04x%04x' \
    $RANDOM \
    $RANDOM \
    $RANDOM \
    $RANDOM \
    $RANDOM \
    $RANDOM \
    $RANDOM \
    $RANDOM \
    ;
}

function OAuth_timestamp {
  date +%s
}

function OAuth_generate {
  typeset realm="$1"; shift
  typeset consumer_key="$1"; shift
  typeset consumer_secret="$1"; shift
  typeset token="$1"; shift
  typeset token_secret="$1"; shift
  typeset callback="$1"; shift
  typeset url="$1"; shift
  typeset method="$1"; shift

  typeset hmac_key="$consumer_secret&$token_secret"
  typeset -a oauth=(
    "oauth_consumer_key=$consumer_key"
    "oauth_signature_method=HMAC-SHA1"
    "oauth_version=1.0"
    "oauth_nonce=$(OAuth_nonce)"
    "oauth_timestamp=$(OAuth_timestamp)"
    ${token:+"oauth_token=$token"}
    ${callback:+"oauth_callback=$callback"}
  )

  typeset oauth_string
  oauth_string=$(
    echo -n "$method&"
    HTTP_pencode "$url"
    echo -n '&'

    for pv in "$@" "${oauth[@]}"; do
      echo "$(HTTP_pencode "${pv%%=*}") $(HTTP_pencode "${pv#*=}")"
    done \
    |sort \
    |sed 's/ /%3D/;s/$/%26/' \
    |tr -d '\n' \
    |sed 's/%26$//' \
    ;
  )
  typeset oauth_signature
  oauth_signature=$(
    echo -n "$oauth_string" \
    |openssl sha1 -hmac "$hmac_key" -binary \
    |openssl base64 \
    |HTTP_pencode \
    ;
  )

  typeset query=
  while [[ $# -gt 0 ]]; do
    query+="$1"
    [[ $# -gt 1 ]] && query+='&'
    shift
  done

  echo "Authorization: OAuth${realm:+ realm=$realm,}"
  typeset pv
  for pv in "${oauth[@]}"; do
    echo " $pv,"
  done
  echo " oauth_signature=$oauth_signature"
}

function Tweet_string_length {
  typeset LC_ALL="$Tweet_lang"
  echo "${#1}"
}

function Tweet_init {
  if [[ -n ${ZSH_VERSION-} ]]; then
    setopt BSD_ECHO
    setopt KSH_GLOB
    setopt TYPESET_SILENT
  elif [[ -n ${BASH_VERSION-} ]]; then
    shopt -u xpg_echo
  else ## ksh
    if [[ $(echo -n) == -n ]]; then
      alias echo='print -r'
    fi
  fi

  typeset lang_orig="${LANG-}"
  typeset locale lang_ja lang
  if [[ ${lang_orig#*.} != @(UTF-8|utf-8|UTF8|utf8) ]]; then
    if type locale >/dev/null 2>&1; then
      while read -r locale; do
	if [[ ${locale#*.} == @(UTF-8|utf-8|UTF8|utf8) ]]; then
	  if [[ ${locale%.*} == ja_JP ]]; then
	    lang_ja="$locale"
	  else
	    lang="$locale"
	  fi
	fi
      done < <(locale -a)
    fi
  fi
  Tweet_lang="${lang_ja-${lang-ja_JP.UTF-8}}"
}

function Tweet_authorize {
  if [[ -n $Tweet_oauth_access_token && -n $Tweet_oauth_access_token_secret ]]; then
    return 0
  fi

  echo "No OAuth access token and/or secret for Twitter access configured."
  echo
  echo "I'll open Twitter site by a WWW browser to get OAuth access token"
  echo "and secret. Please authorize this application and get a PIN code"
  echo "on Twitter site."
  echo
  echo -n "Press Enter key to open Twitter site..."
  read
  echo

  typeset oauth
  oauth=$(
    OAuth_generate \
      "$Tweet_api_url" \
      "$Tweet_oauth_consumer_key" \
      "$Tweet_oauth_consumer_secret" \
      '' \
      '' \
      '' \
      "$Tweet_api_url_request_token" \
      "POST" \
      ;
  )

  typeset response
  response=$(
    HTTPS_request \
      "$Tweet_api_url_request_token" \
      "POST" \
      "$oauth" \
      ;
  )
  typeset rc="$?"
  if [[ $rc -ne 0 ]]; then
    Tweet_error "OAuth request token failed: ${response%%$Tweet_c_lf*}"
    return 1
  fi

  typeset body="${response#*$Tweet_c_lf$Tweet_c_lf}"
  typeset oauth_token=$(HTTP_response_extract "$body" oauth_token)
  typeset oauth_token_secret=$(HTTP_response_extract "$body" oauth_token_secret)

  HTTP_browser "$Tweet_api_url_authorize_token?oauth_token=$oauth_token"

  echo -n 'Enter PIN code: '
  typeset pin=
  read -r pin
  echo

  typeset oauth
  oauth=$(
    OAuth_generate \
      "$Tweet_api_url" \
      "$Tweet_oauth_consumer_key" \
      "$Tweet_oauth_consumer_secret" \
      "$oauth_token" \
      "$oauth_token_secret" \
      '' \
      "$Tweet_api_url_access_token" \
      "POST" \
      "oauth_verifier=$pin" \
      ;
  )

  typeset response
  response=$(
    HTTPS_request \
      "$Tweet_api_url_access_token" \
      "POST" \
      "$oauth" \
      -- \
      "oauth_verifier=$pin" \
      ;
  )
  typeset rc="$?"
  if [[ $rc -ne 0 ]]; then
    Tweet_error "OAuth access token failed: ${response%%$Tweet_c_lf*}"
    return 1
  fi

  typeset body="${response#*$Tweet_c_lf$Tweet_c_lf}"
  Tweet_oauth_access_token=$(HTTP_response_extract "$body" oauth_token)
  Tweet_oauth_access_token_secret=$(HTTP_response_extract "$body" oauth_token_secret)

  if [[ ! -f "$Tweet_conf_file" ]]; then
    echo "Saving OAuth consumer key and secret into $Tweet_conf_file..."
    (umask 0077; touch "$Tweet_conf_file") || return 1
    echo "oauth_consumer_key='$Tweet_oauth_consumer_key'" >>"$Tweet_conf_file"
    echo "oauth_consumer_secret='$Tweet_oauth_consumer_secret'" >>"$Tweet_conf_file"
  fi
  echo "Saving OAuth access token and secret into $Tweet_conf_file..."
  echo "oauth_access_token='$Tweet_oauth_access_token'" >>"$Tweet_conf_file"
  echo "oauth_access_token_secret='$Tweet_oauth_access_token_secret'" >>"$Tweet_conf_file"

  return 0
}

function Tweet_tweet {
  typeset script="$1"; shift

  typeset script_len=$(Tweet_string_length "$script")
  if [[ $script_len -gt $Tweet_script_limit ]]; then
    Tweet_error "Script too long (>$Tweet_script_limit) to tweet: $script_len"
    return 1
  fi

  typeset query
  query="status=$(HTTP_pencode "$script")"

  typeset oauth
  oauth=$(
    OAuth_generate \
      "$Tweet_api_url" \
      "$Tweet_oauth_consumer_key" \
      "$Tweet_oauth_consumer_secret" \
      "$Tweet_oauth_access_token" \
      "$Tweet_oauth_access_token_secret" \
      '' \
      "$Tweet_api_url/statuses/update.json" \
      "POST" \
      "$query" \
      ;
  )

  typeset response
  response=$(
    HTTPS_request \
      "$Tweet_api_url/statuses/update.json" \
      "POST" \
      "$oauth" \
      -- \
      "$query" \
      ;
  )
  typeset rc="$?"
  if [[ $rc -ne 0 ]]; then
    Tweet_error "Tweet failed: ${response%%$Tweet_c_lf*}"
    return 1
  fi

  typeset body="${response#*$Tweet_c_lf$Tweet_c_lf}"
}

function Tweet_command_help {
  echo "Usage: $0 SCRIPT"
  exit 0
}

function Tweet_command {
  if [[ $# -ne 1 ]]; then
    Tweet_command_help
    exit 0
  fi

  if [[ -f "$Tweet_conf_file" ]]; then
    . "$Tweet_conf_file" || exit 1
  fi

  if [[ -n ${oauth_consumer_key-} ]]; then
    Tweet_oauth_consumer_key="$oauth_consumer_key"
  fi
  if [[ -n ${oauth_consumer_secret-} ]]; then
    Tweet_oauth_consumer_secret="$oauth_consumer_secret"
  fi
  if [[ -n ${oauth_access_token-} ]]; then
    Tweet_oauth_access_token="$oauth_access_token"
  fi
  if [[ -n ${oauth_access_token_secret-} ]]; then
    Tweet_oauth_access_token_secret="$oauth_access_token_secret"
  fi

  Tweet_authorize && Tweet_tweet "$@"
  ## FIXME: Parse reply from Twitter.com
  return $?
}

## ======================================================================

if [[ ${0##*/} == echo-sd ]] && [[ ${zsh_eval_context-toplevel} == toplevel ]]; then
  SD_init

  if [[ ${GATEWAY_INTERFACE-} == @(CGI*) ]]; then
    SD_echo_cgi "$@"
  else
    SD_echo_command "$@"
  fi
  exit $?
fi

return 0