呼び出し元：回答消去ボタン押した時
167610
function(){
		var opemgr = this.puzzle.opemgr;
		opemgr.newOperation();
		opemgr.add(new this.puzzle.klass.BoardClearOperation());
		
		this.cell.ansclear();
		this.cross.ansclear();
		this.border.ansclear();
		this.excell.ansclear();
		opemgr.rejectTrial(true);
		if(opemgr.history[opemgr.history.length-1].length===1){
			opemgr.puzzle.undo();
			opemgr.removeDescendant();
		}
		
		this.rebuildInfo();
	}
133508
function tokenize(str) {
  var lines = str.split(LB_RE);
  var line;
  var tokens = [];

  // 空文字は無視します
  if (str.length === 0) { return tokens; }

  var isCGMD = false;
  // 全ての行をなめる
  while ((line = lines.shift()) !== undefined) {
    // CGMDのスタート / エンドでフラグを打つ
    if (CGMD_START_RE.exec(line.trim())) {
      isCGMD = true;
      tokens.push(new CGMD_Token());
      tokens[tokens.length - 1].addBody(line);
      continue;
    }
    if (CGMD_END_RE.exec(line.trim())) {
      isCGMD = false;
      tokens[tokens.length - 1].addBody(line);
      continue;
    }

    if (
      // ふつうのMDでありつつ
      isCGMD === false &&
      (
        // 最初か
        tokens.length === 0 ||
        // さっきまでCGMDを処理していたなら
        tokens[tokens.length - 1].isTypeCGMD()
      )
    ) {
      // 新しい区分にしてから
      tokens.push(new MD_Token());
    }

    // 中身を入れる
    tokens[tokens.length - 1].addBody(line);
  }

  // 全行見終わってまだこのフラグが立ってるなら閉じ忘れ
  if (isCGMD) {
    throw new Error('Missing close tag for CGMD!');
  }

  return tokens;
}
317823
function ( el, type ) {
                var eventIds = el.__ix_eventIds__;
                //등록된 _ix_eventIds_가 없으면 정지.
                if ( !eventIds ) return;
    
                //type = getCrossType( type );
    
                //가장최근에 등록된 이벤트가 제거될 가능성이 높기때문에 루프를 뒤에서 부터 돈다.
                for ( var i = eventIds.length - 1; i >= 0; --i ) {
                    var id = eventIds[i],
                        evt = window.__ix_allEvents__[id];
    
                    if ( evt.type == type ) {
                        this._removeEventListener( el, type, evt.wrapHandler );
                        //배열에서 el 제거
                        el.__ix_eventIds__.splice( i, 1 );
                        //창마다 하나식 있는 __ix_allEvents__ 객체에서 이벤트정보 삭제
                        delete window.__ix_allEvents__[id];
                    }
                }
            }
437630
function(){
		// とりあえず盤面全部の対応だけ
		var d0 = this.area, d = {x1:d0.x1,y1:d0.y1,x2:d0.x2,y2:d0.y2};
		var key_undo = this.board.exec.boardtype[this.old][0];
		if(key_undo & this.TURN){ var tmp=d.x1;d.x1=d.y1;d.y1=tmp;}
		this.exec(key_undo,d);
	}
352340
function handleFieldsTree (api) {
            // 排除名单
            var ex = ['function', 'desc', 'param', 'example'];
            if ( api && typeof api === 'object' ) {
                for ( var i in api ) {
                    if ( ex.indexOf(i) === -1 ) {
                    // grunt.log.writeln(i)
                        var field = api[i];
                        // console.log(field)
                        var tmp = [];
                        // grunt.log.writeflags(field)
                        if ( field && field.forEach ) {
                            field.forEach(function (item, k) {
                                if ( item.belong ) {
                                    tmp.push(k);
                                    handleFieldBelong(i, item.belong.split('.'), api.param, item)
                                }
                            });
                            if ( tmp.length ) {
                                for ( var m = tmp.length; m-- ; m >= 0 ) {
                                    // console.log(tmp[m])
                                    field.splice(tmp[m],1)
                                }
                            }
                            // clear
                            if ( !field.length ) delete api[i];

                        }
                    }
                }
            }
        }
196630
public function automatic_rest_api(){
		@header('text/json; charset=UTF-8');

		$rtn = array();
		$rtn['result'] = false;
		// $rtn['options'] = $this->options;
		// $rtn['_SERVER'] = $_SERVER;
		// $rtn['_GET'] = $_GET;
		// $rtn['_POST'] = $_POST;

		if( $this->options['method'] == 'POST' ){
			// --------------------------------------
			// 投稿系リクエスト
			if( !strlen($this->options['table']) ){
				// 対象のテーブルが不明な場合はエラー
				$rtn['error'] = 'Table name not set.';
				echo json_encode( $rtn );
				return null;
			}
			if( strlen($this->options['id']) ){
				// 対象のテーブルが指定された場合はエラー
				$rtn['error'] = 'Resource ID was set.';
				echo json_encode( $rtn );
				return null;
			}

			$params = $this->options['post_params'];
			$result = $this->exdb->insert($this->options['table'], $params);
			$rtn['result'] = $result;
			$last_insert_info = $this->exdb->get_last_insert_info();
			$rtn['given_id'] = $last_insert_info->value;
			echo json_encode( $rtn );
			return null;

		}elseif( $this->options['method'] == 'GET' ){
			// --------------------------------------
			// 取得系リクエスト
			if( !strlen($this->options['table']) ){
				// 対象のテーブルが不明な場合はエラー
				$rtn['error'] = 'Table name not set.';
				echo json_encode( $rtn );
				return null;
			}

			if( !strlen($this->options['id']) ){
				// ID無指定の場合、一覧情報を返す
				$rtn['list'] = $this->exdb->select($this->options['table'], $this->options['get_params'], $this->query_options);
				$rtn['count'] = $this->exdb->count($this->options['table'], $this->options['get_params']);
				$rtn['result'] = true;
				if( count($this->table_definition->system_columns->password) ){
					foreach( $rtn['list'] as $key=>$val ){
						foreach($this->table_definition->system_columns->password as $column_name){
							unset($rtn['list'][$key][$column_name]);
						}
					}
				}
				echo json_encode( $rtn );
				return null;
			}else{
				// ID指定がある場合、詳細情報1件を返す
				$where = $this->options['get_params'];
				// $rtn['table_definition'] = $this->table_definition;
				$where[$this->table_definition->key_column] = $this->options['id'];
				$row = $this->exdb->select($this->options['table'], $where);
				$rtn['row'] = @$row[0];
				foreach($this->table_definition->system_columns->password as $column_name){
					unset($rtn['row'][$column_name]);
				}
				$rtn['result'] = true;
				echo json_encode( $rtn );
				return null;
			}

		}elseif( $this->options['method'] == 'PUT' ){
			// --------------------------------------
			// 更新系リクエスト
			if( !strlen($this->options['table']) ){
				// 対象のテーブルが不明な場合はエラー
				$rtn['error'] = 'Table name not set.';
				echo json_encode( $rtn );
				return null;
			}
			if( !strlen($this->options['id']) ){
				// 対象のテーブルが不明な場合はエラー
				$rtn['error'] = 'Resource ID not set.';
				echo json_encode( $rtn );
				return null;
			}

			$params = $this->options['post_params'];
			$result = $this->exdb->update(
				$this->options['table'],
				array(
					$this->table_definition->key_column => $this->options['id'],
				),
				$params
			);
			$rtn['result'] = ($result ? true : false);
			$rtn['affected_rows'] = $result;
			echo json_encode( $rtn );
			return null;

		}elseif( $this->options['method'] == 'DELETE' ){
			// --------------------------------------
			// 削除系リクエスト
			if( !strlen($this->options['table']) ){
				// 対象のテーブルが不明な場合はエラー
				$rtn['error'] = 'Table name not set.';
				echo json_encode( $rtn );
				return null;
			}
			if( !strlen($this->options['id']) ){
				// 対象のテーブルが不明な場合はエラー
				$rtn['error'] = 'Resource ID not set.';
				echo json_encode( $rtn );
				return null;
			}

			$result = $this->exdb->delete(
				$this->options['table'],
				array(
					$this->table_definition->key_column => $this->options['id'],
				)
			);
			$rtn['result'] = ($result ? true : false);
			$rtn['affected_rows'] = $result;
			echo json_encode( $rtn );
			return null;

		}

		$rtn['error'] = 'Unknown method';

		echo json_encode( $rtn );
		return null;
	}
585606
function (element, type, handler, context) {
            var own = this;
            //非Dom元素不处理
            if (!(1 == element.nodeType || element.nodeType == 9 || element === window)|| !vQ.isFunction(handler)) {
                return;
            }
            //获取传入参数
            var args = slice.call(arguments);

            //批量绑定事件处理
            if (vQ.isArray(type)) {
                return own._handleMultipleEvents.apply(own, [own.one].concat(args));
                //return own._handleMultipleEvents(own.one, element, type, handler);
            }

            var func = function () {
                own.unbind(element, type, func);
                handler.apply(context || element, arguments);
            };

            // copy the guid to the new function so it can removed using the original function's ID
            func.$$guid = handler.$$guid = handler.$$guid || own._guid++;
            own.bind(element, type, func);


            //var func = function(){
            //    own.unbind.apply(own,args);
            //    handler.apply(context || element, arguments);
            //};
            ////args = [type, func].concat(args.slice(2));//更换fun 这样支持不定个数的参数
            //
            //// copy the guid to the new function so it can removed using the original function's ID
            //func.$$guid = handler.$$guid = handler.$$guid || own._guid++;
            ////own.observe(element, type, func);
            //own.bind.apply(own,args);
        }
604068
function (name, value) {
            var self = this, setValue,
                // if host does not have meta info corresponding to (name,value)
                // then register on demand in order to collect all data meta info
                // 一定要注册属性元数据，否则其他模块通过 _attrs 不能枚举到所有有效属性
                // 因为属性在声明注册前可以直接设置值
                attrConfig = ensureNonEmpty(self.getAttrs(), name), setter = attrConfig.setter;    // if setter has effect
            // if setter has effect
            if (setter && (setter = normalFn(self, setter))) {
                setValue = setter.call(self, value, name);
            }
            if (setValue === INVALID) {
                return FALSE;
            }
            if (setValue !== undefined) {
                value = setValue;
            }    // finally set
            // finally set
            getAttrVals(self)[name] = value;
            return undefined;
        }
393475
function(){
		// this.bodyが空の場合はEncode.jsの仕様により対象外
		// カンペンには以下のパズルは存在しないのでURL_KANPENPも対象外
		if(!this.body || (this.type!==URL_PZPRV3 && this.type!==URL_PZPRAPP)){ return;}
		
		switch(this.pid){
		case 'ichimaga':
			if     (this.pflag.indexOf('m')>=0){ this.pid = 'ichimagam';}
			else if(this.pflag.indexOf('x')>=0){ this.pid = 'ichimagax';}
			else                               { this.pid = 'ichimaga'; }
			break;
		case 'icelom':
			if(this.pflag.indexOf('a')<0){ this.pid = 'icelom2';}
			break;
		case 'pipelink':
			if(this.body.match(/[0-9]/)){ this.pid = 'pipelinkr';}
			break;
		case 'bonsan':
			if(this.pflag.indexOf('c')<0){
				var col = this.cols, row = this.rows;
				if(this.body.substr(0,((((col-1)*row+4)/5)|0)+(((col*(row-1)+4)/5)|0)||0).match(/[^0]/)){
					this.pid = 'heyabon';
				}
			}
			break;
		case 'kramma':
			if(this.pflag.indexOf('c')<0){
				var len=(this.cols-1)*(this.rows-1), cc=0;
				for(var i=0;i<this.body.length;i++){
					var ca = this.body.charAt(i);
					if(ca.match(/\w/)){
						cc += parseInt(ca,36);
						if(cc<len){ this.pid = 'kramman'; break;}
					}
					else if(ca === '.'){ cc+=36;}
					if(cc>=len){ break;}
				}
			}
			break;
		}
	}
1027888
function isOTag (str, oTag, index) {
    var l = oTag.length, s = str.substr(index, l), sign = str.charAt(index+l);
    // NOTE 要保证sign有值 如果当前的index已经是字符串尾部 如'foo{{' sign为空
    if (oTag === s && sign && SIGN.indexOf(sign) > -1) {
        return {
            str: s + sign,
            index: index,
            // sign: signType[str.charAt(index+l)], // TODO: delete
            sign: str.charAt(index+l),
            // ignore the last oTag charts and the sign char,
            // l(oTag.length) - 1(oTag's first char) + 1(sign's char)
            jump: l
        };
    }
}
174023
function (uri, fromUri, source) {
        if (!/^\./.test(uri) || EXTNAME_RE.test(uri)) {

            var line;

            // 如果只出现一次这个字符串，很容易确认模板错误行
            if (source.split(uri).length === 2) {
                source.split(/\n/).forEach(function (code, index) {
                    if (code.indexOf(uri) !== -1) {
                        line = index + 1;
                        source = code.trim();
                    }
                });
            }

            var error = {
                name: 'Syntax Error',
                line: line,
                source: source,
                message: 'Template must be a relative path, and can not have a suffix.'
            };

            if (fromUri) {
                error.filename = fromUri;
            }

            throw error;
        }
    }
677413
function (element, type, handler, context) {
            var own = this;

            //非DOM元素不处理 handler 非function 不处理
            if (!(1 == element.nodeType || element.nodeType == 9 || element === window) || !vQ.isFunction(handler)) {
                return;
            }

            //多个事件处理
            if (vQ.isArray(type)) {
                return own._handleMultipleEvents(own.observe, element, type, handler);
            }

            var _handler = handler;

            //上下文对象处理
            if (context) {
                _handler = function () {
                    handler.apply(context, arguments);
                };
                own._contextHandler[handler.$$guid] = _handler;
                _handler.$$guid = handler.$$guid = handler.$$guid || own._guid++;
            }

            //调用原生方法绑定事件
            if (element.addEventListener) {
                element.addEventListener(type, _handler, false);
            } else {
                //IE等 自行托管事件

                // assign each event handler a unique ID
                if (!_handler.$$guid) _handler.$$guid = this._guid++;
                // create a hash table of event types for the element
                if (!element.events) element.events = {};
                // create a hash table of event handlers for each element/event pair
                var handlers = element.events[type];
                if (!handlers) {
                    handlers = element.events[type] = {};
                    // store the existing event handler (if there is one)
                    if (element['on' + type]) {
                        handlers[0] = element['on' + type];
                    }
                }
                // store the event handler in the hash table
                handlers[_handler.$$guid] = _handler;
                // assign a global event handler to do all the work
                element['on' + type] = own._handleEvent;
            }
        }
486531
private function f1()
    {
        $_linkstr = "\n<p class=\"links\">\n"; //begin
        if ($this->totalpage < 2) {
            $nextpage = $this->cpage + 1;
            $_linkstr .= "<span class=\"disabled\">首页</span>" . " \n";
            $_linkstr .= "<span class=\"disabled\">上一页</span> \n";
            $_linkstr .= "<span class=\"disabled\">下一页</span> \n";
            $_linkstr .= "<span class=\"disabled\">尾页</span> \n";
        } elseif ($this->cpage < 2) {
            // 首页
            $nextpage = $this->cpage + 1;
            $_linkstr .= "<span class=\"disabled\">首页</span>" . " \n";
            $_linkstr .= "<span class=\"disabled\">上一页</span> \n";
            $_linkstr .= "<a href=\"" . $this->url ( $nextpage ) . "\">下一页</a> \n";
            $_linkstr .= "<a href=\"" . $this->url ( $this->totalpage ) . "\">尾页</a> \n";
        } elseif ($this->cpage >= $this->totalpage) {
            // ＝尾页
            $prepage = $this->cpage - 1;

            $_linkstr .= "<a href=\"" . $this->url ( 1 ) . "\">首页</a>\n";
            $_linkstr .= "<a href=\"" . $this->url ( $prepage ) . "\">上一页</a>\n";
            $_linkstr .= "\n<span class=\"disabled\">下一页</span>\n";
            $_linkstr .= "<span class=\"disabled\">尾页</span>" . "\n";
        } else {
            // 正常
            $prepage  = $this->cpage - 1;
            $nextpage = $this->cpage + 1;

            $_linkstr .= "<a href=\"" . $this->url ( 1 ) . "\">首页</a>\n";
            $_linkstr .= "<a href=\"" . $this->url ( $prepage ) . "\">上一页</a>\n";
            $_linkstr .= "\n<a href=\"" . $this->url ( $nextpage ) . "\">下一页</a>\n";
            $_linkstr .= "<a href=\"" . $this->url ( $this->totalpage ) . "\">尾页</a>\n";
        }
        $_linkstr .= "</p>\n"; //end div
        return $_linkstr;
    }
1298498
function ( el, selector ) {
            //el = $B( el ).element();
            //이미 파싱된 Object면 다시 파싱하지 않는다.
            var matchList = (typeof selector === 'string')? this.parse( selector ) : selector,
                result = false, n;
    
            for ( n in matchList ) {
                switch ( n ) {
                    case 'node':
                        var node = el.nodeName;
    
                        if ( node ) {
                            node = node.toLowerCase();
                            result = ( node == matchList[n] );
                        } else {
                            result = false;
                        }
                        break;
                    case 'id':
                        result = ( $B(el).attr('id') == matchList[n] );
                        break;
                    case 'className':
                        result = $B( el ).hasClass( matchList[n] );
                        break;
                    case 'attr':
                        result = this.matchAttr( el, matchList[n] );
                        break;
                }
                //하나라도 false가 나오면 더이상 체크하지 않는다.
                if ( !result ) return result;
            }
    
            return result;
        }
1006796
function (_this) {
    // 抽屉栏滑动手势控制
    var openNavEventHandler;
    var touchStartX;
    var touchStartY;
    var swipeStartX;
    var swiping = false;
    var maybeSwiping = false;
    var $body = $('body');

    // 手势触发的范围
    var swipeAreaWidth = 24;

    function enableSwipeHandling() {
      if (!openNavEventHandler) {
        $body.on('touchstart', onBodyTouchStart);
        openNavEventHandler = onBodyTouchStart;
      }
    }

    function setPosition(translateX, closeTransform) {
      var rtlTranslateMultiplier = _this.position === 'right' ? -1 : 1;
      var transformCSS = 'translate(' + (-1 * rtlTranslateMultiplier * translateX) + 'px, 0) !important;';
      _this.$drawer.css(
        'cssText',
        'transform:' + transformCSS + (closeTransform ? 'transition: initial !important;' : '')
      );
    }

    function cleanPosition() {
      _this.$drawer.css({
        transform: '',
        transition: '',
      });
    }

    function getMaxTranslateX() {
      return _this.$drawer.width() + 10;
    }

    function getTranslateX(currentX) {
      return Math.min(
        Math.max(
          swiping === 'closing' ? (swipeStartX - currentX) : (getMaxTranslateX() + swipeStartX - currentX),
          0
        ),
        getMaxTranslateX()
      );
    }

    function onBodyTouchStart(event) {
      touchStartX = event.touches[0].pageX;
      if (_this.position === 'right') {
        touchStartX = $body.width() - touchStartX;
      }

      touchStartY = event.touches[0].pageY;

      if (_this.state !== 'opened') {
        if (touchStartX > swipeAreaWidth || openNavEventHandler !== onBodyTouchStart) {
          return;
        }
      }

      maybeSwiping = true;

      $body.on({
        touchmove: onBodyTouchMove,
        touchend: onBodyTouchEnd,
        touchcancel: onBodyTouchMove,
      });
    }

    function onBodyTouchMove(event) {
      var touchX = event.touches[0].pageX;
      if (_this.position === 'right') {
        touchX = $body.width() - touchX;
      }

      var touchY = event.touches[0].pageY;

      if (swiping) {
        setPosition(getTranslateX(touchX), true);
      } else if (maybeSwiping) {
        var dXAbs = Math.abs(touchX - touchStartX);
        var dYAbs = Math.abs(touchY - touchStartY);
        var threshold = 8;

        if (dXAbs > threshold && dYAbs <= threshold) {
          swipeStartX = touchX;
          swiping = _this.state === 'opened' ? 'closing' : 'opening';
          $.lockScreen();
          setPosition(getTranslateX(touchX), true);
        } else if (dXAbs <= threshold && dYAbs > threshold) {
          onBodyTouchEnd();
        }
      }
    }

    function onBodyTouchEnd(event) {
      if (swiping) {
        var touchX = event.changedTouches[0].pageX;
        if (_this.position === 'right') {
          touchX = $body.width() - touchX;
        }

        var translateRatio = getTranslateX(touchX) / getMaxTranslateX();

        maybeSwiping = false;
        var swipingState = swiping;
        swiping = null;

        if (swipingState === 'opening') {
          if (translateRatio < 0.92) {
            cleanPosition();
            _this.open();
          } else {
            cleanPosition();
          }
        } else {
          if (translateRatio > 0.08) {
            cleanPosition();
            _this.close();
          } else {
            cleanPosition();
          }
        }

        $.unlockScreen();
      } else {
        maybeSwiping = false;
      }

      $body.off({
        touchmove: onBodyTouchMove,
        touchend: onBodyTouchEnd,
        touchcancel: onBodyTouchMove,
      });
    }

    if (_this.options.swipe) {
      enableSwipeHandling();
    }
  }
1237142
function otfContours2ttfContours(otfContours) {
            if (!otfContours || !otfContours.length) {
                return otfContours;
            }
            var contours = [];
            for (var i = 0, l = otfContours.length; i < l; i++) {

                // 这里可能由于转换错误导致空轮廓，需要去除
                if (otfContours[i][0]) {
                    contours.push(transformContour(otfContours[i]));
                }
            }

            return contours;
        }
291690
def e2h(string):
    
    ctx = Context(string)
    for char in ctx.input:
        hchar = E2H_MAPPING.get(char)

        if not char.isalpha() or not hchar:
            ctx.do_final()
            ctx.output.append(char)
            ctx.state = State.INIT
            continue

        if ctx.state is State.INIT:
            if hchar not in JA_LEAD:
                ctx.output.append(hchar)
            else:
                ctx.state = State.LEAD_GIVEN
                ctx.pending.append(hchar)

        elif ctx.state is State.LEAD_GIVEN:
            if hchar in MO:  # ㅇ + ㅏ
                ctx.state = State.MEDI_GIVEN
                ctx.pending.append(hchar)
            else:  # ㅇ + ㅇ
                ctx.state = State.INIT
                ctx.pending.append(hchar)
                ctx.flush()

        elif ctx.state is State.MEDI_GIVEN:
            if hchar in JA:  # ㅇ + ㅏ + ㅇ
                ctx.state = State.TAIL_GIVEN
                ctx.pending.append(hchar)
            else:
                compose_waiter = ctx.pending[-1]
                compose_tuple = JAMO_COMPOSE_TABLE.get(compose_waiter)

                if compose_tuple and hchar in compose_tuple:  # (ㅇ + ㅗ + ㅏ)
                    ctx.pending[-1] = chr((ord(compose_waiter) + compose_tuple.index(hchar) + 1))
                else:  # (ㅇ + ㅏ + ㅏ)
                    ctx.do_final()
                    ctx.state = State.INIT
                    ctx.output.append(hchar)

        elif ctx.state is State.TAIL_GIVEN:
            if hchar in MO:
                if len(ctx.composing_tails) == 2:  # (ㅇ + ㅓ + ㄵ + ㅔ ==> 언제)
                    ctx.pending.pop()  # drop 'ㄵ'
                    ctx.do_final(ctx.composing_tails.pop(0))  # (ㅇ + ㅓ + ㄴ)
                    ctx.pending.append(ctx.composing_tails.pop())  # (ㅈ)
                    ctx.pending.append(hchar)  # (ㅈ + ㅔ)
                    ctx.state = State.MEDI_GIVEN
                else:  # ㄱ,ㅏ,ㅅ  + ㅏ ==> 가,사
                    last_hchar = ctx.pending.pop()
                    ctx.do_final()
                    ctx.pending.append(last_hchar)
                    ctx.pending.append(hchar)
                    ctx.state = State.MEDI_GIVEN
            else:
                compose_waiter = ctx.pending[-1]
                compose_tuple = JAMO_COMPOSE_TABLE.get(compose_waiter)

                if compose_tuple and hchar in compose_tuple:  # (ㄷ + ㅏ + ㄹ + ㄱ)
                    ctx.pending[-1] = chr((ord(compose_waiter) + compose_tuple.index(hchar) + 1))

                    ctx.composing_tails.clear()
                    ctx.composing_tails.append(compose_waiter)
                    ctx.composing_tails.append(hchar)

                else:  # (ㄷ + ㅏ + ㅂ + ㄱ) or (ㄷ + ㅏ + ㄹ + ㄱ + ㄱ)
                    ctx.do_final()
                    ctx.state = State.LEAD_GIVEN
                    ctx.pending.append(hchar)
                    ctx.composing_tails.clear()

    ctx.do_final()  # finalize remain character if any
    return ''.join(ctx.output)