Jinja: ์žฌ์ •์˜ ๊ฐ€๋Šฅํ•œ ์ž๋™ ์ด์Šค์ผ€์ดํ”„

์— ๋งŒ๋“  2015๋…„ 10์›” 15์ผ  ยท  11์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: pallets/jinja

์ง์žฅ์—์„œ ์šฐ๋ฆฌ๋Š” ํ…œํ”Œ๋ฆฟ์„ YAML๋กœ ๋ Œ๋”๋งํ•˜๊ธฐ ์œ„ํ•ด Jinja๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋ชจ๋“  {{ variable }} ํ™•์žฅ์„ ์‚ฌ์šฉ์ž ์ •์˜ํ•˜์—ฌ None (YAML์—์„œ null ์ž„) ๋ฐ ๋นˆ ๋ฌธ์ž์—ด( '' ๋กœ ์ธ์ฝ”๋”ฉ๋จ)๊ณผ ๊ฐ™์€ Python ๊ฐ’์— ์ ํ•ฉํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค '' ). Jinja ์ž๋™ ์ด์Šค์ผ€์ดํ”„ ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด ์ด์— ์ ํ•ฉํ•  ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋ถˆํ–‰ํžˆ๋„ HTML๋กœ ์ž๋™ ์ด์Šค์ผ€์ดํ”„ํ•˜์ง€ ์•Š๋„๋ก ์ž๋™ ์ด์Šค์ผ€์ดํ”„ ๊ธฐ๋Šฅ์„ ๊ตฌ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์—†์Šต๋‹ˆ๋‹ค. ๋Œ€์‹ ์—, ๋‚˜๋Š” monkeypatch ํ–ˆ์–ด Markup ๋ฐ escape ์— jinja2.runtime . ์˜ˆ๋ฅผ ๋“ค์–ด ํ™˜๊ฒฝ์—์„œ ๋ฌด์–ธ๊ฐ€๋ฅผ ์žฌ์ •์˜ํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์ด ๊ณต์‹์ ์œผ๋กœ ์Šน์ธ๋œ ๋ฐฉ๋ฒ•์ด ์žˆ์œผ๋ฉด ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋ชจ๋“  11 ๋Œ“๊ธ€

์ž๋™ ์ด์Šค์ผ€์ดํ”„๊ฐ€ ์ด๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ์ ์ ˆํ•œ ๋ฐฉ๋ฒ•์ธ์ง€ ํ™•์‹คํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

ํ•„ํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. tojson ๋Š” yaml์ด json์˜ ์ƒ์œ„ ์ง‘ํ•ฉ์ด๊ธฐ ๋•Œ๋ฌธ์— ์ข‹์€ ํ›„๋ณด๋กœ ๋ณด์ž…๋‹ˆ๋‹ค.


๊ทธ ์™ธ์—๋„ YAML์„ ๋นŒ๋“œํ•˜๊ธฐ ์œ„ํ•ด ๋ฌธ์ž์—ด ๊ธฐ๋ฐ˜ ํ…œํ”Œ๋ฆฟ์„ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ ๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ? Python ์‚ฌ์ „์„ YAML๋กœ ์ง๋ ฌํ™”ํ•˜๋Š” ๊ฒƒ์ด ํ›จ์”ฌ ๊น”๋”ํ•ด ๋ณด์ž…๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ์ถฉ๋ถ„ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ๋Š” ์œ ์ผํ•œ ๊ฒฝ์šฐ๋Š” ์ฃผ์„์„ ํฌํ•จํ•˜๋ ค๋Š” ๊ฒฝ์šฐ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด ๊ฒฝ์šฐ ๋น„ํŒŒ๊ดด์  ์ฝ๊ธฐ/์“ฐ๊ธฐ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” YAML ์—”์ง„์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์ฃผ์„๊ณผ ๋นˆ ํ•ญ๋ชฉ์ด ์žˆ๋Š” YAML ํ…œํ”Œ๋ฆฟ์„ ๋กœ๋“œํ•œ ๋‹ค์Œ ๋ฐ์ดํ„ฐ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๊ณ  YAML๋กœ ๋‹ค์‹œ ์ง๋ ฌํ™”ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

์ž๋™ ์ด์Šค์ผ€์ดํ”„๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์š”์ ์€ ๋ชจ๋“  ๋‹จ์ผ ๋ณ€์ˆ˜ ํ™•์žฅ์— ํ•„ํ„ฐ๋ฅผ ์ ์šฉํ•˜๊ณ  ์‹ถ์ง€ ์•Š๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์šฐ๋ฆฌ์˜ ์‚ฌ์šฉ ์‚ฌ๋ก€๋Š” ๋งˆ์ดํฌ๋กœ ์„œ๋น„์Šค์— ๋Œ€ํ•œ ๊ตฌ์„ฑ ํŒŒ์ผ์„ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ฐ ์„œ๋น„์Šค์— ํฌํ•จ๋œ "ํ…œํ”Œ๋ฆฟ"์ด ์žˆ์œผ๋ฉฐ ํ•ด๋‹น ํ…œํ”Œ๋ฆฟ์— ํŠน์ •ํ•œ ํ™˜๊ฒฝ๋ณ„ ๊ตฌ์„ฑ์œผ๋กœ ์ฑ„์šฐ๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” YAML์„ ์ง์ ‘ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋” ๊นจ๋—ํ•˜๋‹ค๋Š” ๋ฐ ๋™์˜ํ•˜์ง€๋งŒ ์•„์ง ์œ„์น˜๋ฅผ ์•Œ์ง€ ๋ชปํ•˜๋Š” ๋ณ€์ˆ˜๋ฅผ ๋Œ€์ฒดํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ๊ณ  ์žˆ๋Š” ์ผ๋ฐ˜ "์—”์ง„"์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. (YAML ๋ณ„์นญ๊ณผ ์ฐธ์กฐ๊ฐ€ ์žˆ์ง€๋งŒ ์‹ค์ œ๋กœ๋Š” ์ ํ•ฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ˆœํ™˜ ๊ตฌ์กฐ๋ฅผ ์ง๋ ฌํ™”ํ•˜๋Š” ๋ฐ ๋” ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค.) YAML์„ ์‚ฌ์šฉํ•˜์—ฌ ์ด๊ฒƒ์„ ์ž‘๋™ํ•˜๊ฒŒ ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์ผ์ข…์˜ ํ•ดํ‚ค๋„. ์ด ์„ค์ •์€ ๋˜ํ•œ ์šฐ๋ฆฌ๊ฐ€ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ๋Œ€์ฒด ์œ ํ˜•์— ๋Œ€ํ•œ ๋” ๋งŽ์€ ์ œ์–ด๋ฅผ ์ œ๊ณตํ•˜์ง€๋งŒ ์‹ค์ œ๋กœ๋Š” ์‹ค์ œ๋กœ ์ด๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

jinja ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ชจ๋“  ๋ณ€์ˆ˜์— ํ•„ํ„ฐ๋ฅผ ์ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. i18n ๋ธ”๋ก์„ ์‚ฌ์šฉํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค๋ฉด ๊ทธ๋ ‡๊ฒŒ ์–ด๋ ต์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ์–ผ๋งˆ ์ „์— ์ž‘์„ฑํ•œ ๊ฒƒ์—์„œ ์•„์ด๋””์–ด๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. https://github.com/indico/indico/blob/master/indico/web/flask/templating.py#L187

์ด๊ฒƒ์€ ๋งค์šฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค. ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค! ์˜ˆ๋ฅผ ๋“ค์–ด ๋ณ€์ˆ˜์— |safe ํ”Œ๋ž˜๊ทธ๋ฅผ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ž๋™ ์ด์Šค์ผ€์ดํ”„๊ฐ€ ์—ฌ์ „ํžˆ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐ ๊ดœ์ฐฎ์€ ์ ‘๊ทผ ๋ฐฉ์‹์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๊ฐœ๋…์ ์œผ๋กœ ์ด๊ฒƒ์€ ์ž๋™ ์ด์Šค์ผ€์ดํ”„์™€ ๊ฐ™์ง€ ์•Š๋‹ค๋Š” ์ ์„ ์ธ์ •ํ•ฉ๋‹ˆ๋‹ค. ๋ณ€์ˆ˜๊ฐ€ ์œ ํšจํ•œ YAML์ธ์ง€ ํ™•์ธํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ํŠน์ • ๋ฐฉ์‹์œผ๋กœ ํ˜•์‹์„ ์ง€์ •ํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ํ™•์žฅ์ž๋ฅผ ์“ฐ๊ฒ ์Šต๋‹ˆ๋‹ค.

@glasserc ์ด ํ™•์žฅ์œผ๋กœ ์„ฑ๊ณตํ•˜์…จ๋‚˜์š”? ๋น„์Šทํ•œ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•ด๊ฒฐ์ฑ…์„ ์ง€์ ํ•˜๊ฑฐ๋‚˜ ๋ช‡ ๊ฐ€์ง€ ์•„์ด๋””์–ด๋ฅผ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

๋‚ด ์†”๋ฃจ์…˜์˜ ์ฒซ ๋ฒˆ์งธ ๋ถ€๋ถ„์€ ํ•„ํ„ฐ๋ฅผ ํ†ตํ•ด ๋ชจ๋“  ๋ณ€์ˆ˜ ํ˜ธ์ถœ์„ ์‹คํ–‰ํ•˜๋Š” ํ™•์žฅ์ด์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ๋‚ด๊ฐ€ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐ ํ•„์š”ํ•œ ์ตœ์†Œํ•œ์˜ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

import jinja2.ext
from jinja2.lexer import Token

class YAMLEverythingExtension(jinja2.ext.Extension):
    """
    Insert a `|yaml` filter at the end of every variable substitution.

    This will ensure that all injected values are converted to YAML.
    """
    def filter_stream(self, stream):
        # This is based on https://github.com/indico/indico/blob/master/indico/web/flask/templating.py.
        for token in stream:
            if token.type == 'variable_end':
                yield Token(token.lineno, 'pipe', '|')
                yield Token(token.lineno, 'name', 'yaml')
            yield token

์˜ˆ๋ฅผ ๋“ค์–ด ๋ณ€์ˆ˜ ๋ธ”๋ก์— ๋ช…์‹œ์ ์œผ๋กœ safe ๋˜๋Š” yaml ํ•„ํ„ฐ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ํ•„ํ„ฐ ์‚ฝ์ž…์„ ๊ฑด๋„ˆ๋›ธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋‚˜๋Š” ๊ฒฐ์ฝ” ๊ทธ๊ฒƒ์„ ์œ„ํ•œ ์‹œ๊ฐ„์„ ํ•„์š”๋กœ/๊ฐ€์ง€๋Š” ๊ฒƒ์„ ๋๋‚ด์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค.

๋‘ ๋ฒˆ์งธ ๋ถ€๋ถ„์€ ํ•„ํ„ฐ ์ž์ฒด์ž…๋‹ˆ๋‹ค. yaml.dump ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๋งŒ์œผ๋กœ๋Š” ์ถฉ๋ถ„ํžˆ ์ •๊ตํ•˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— yaml ๋‚ด๋ถ€๋ฅผ ์•ฝ๊ฐ„ ์ฐ”๋Ÿฌ์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค.

import cStringIO
import yaml

def yaml_filter(val):
    """Serialize some value in isolation, not as part of any document.

    We can't just use yaml.dump because that outputs an entire document, including newlines, which isn't helpful for
    inserting into a YAML document."""
    if isinstance(val, jinja2.Undefined):
        val._fail_with_undefined_error()
    stream = cStringIO.StringIO()
    dumper = yaml.dumper.Dumper(stream)
    dumper.open()
    node = dumper.represent_data(val)
    dumper.serialize(node)
    # The serialized node tends to have a \n at the end.  The template might not
    # want a \n inserted here, e.g. if two variables are on the same line, so
    # strip.
    return stream.getvalue().strip()

์ด๊ฒƒ์€ ์ฃผ์–ด์ง„ ์ด๋ฆ„์˜ ํ•„ํ„ฐ๊ฐ€ ํ™˜๊ฒฝ์—์„œ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ์ง€ ํ™•์ธํ•˜๋Š” ๊ฒƒ์„ ํฌํ•จํ•˜์—ฌ ๋ชจ๋“  ๊ฒƒ์„ ํ•˜๋‚˜๋กœ ๋ฌถ์Šต๋‹ˆ๋‹ค.

from jinja2 import loaders
from jinja2 import Environment, StrictUndefined

def get_environment():
    """Create a standard Jinja environment that has everything in it.
    """
    jinja_env = Environment(extensions=(YAMLEverythingExtension,),
                            # some other options that we use at work
                            loader=loaders.FileSystemLoader(['.', '/']),
                            undefined=StrictUndefined)
    jinja_env.filters["yaml"] = yaml_filter
    return jinja_env

์ด๊ฒƒ์€ HTML์ด ์•„๋‹Œ ํ…œํ”Œ๋ฆฟ์„ ์ด์Šค์ผ€์ดํ”„ํ•˜๋Š” ๋ฐ ์—ฌ์ „ํžˆ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. Jinja2๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ JSON์„ ์ƒ์„ฑํ•˜๊ณ  HTML ์ด์Šค์ผ€์ดํ”„ ๋Œ€์‹  JSON ์ด์Šค์ผ€์ดํ”„๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.

JSON์„ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•ด Jinja ํ…œํ”Œ๋ฆฟ ๋˜๋Š” ๊ธฐํƒ€ ๋ฌธ์ž์—ด ๊ธฐ๋ฐ˜ ํ…œํ”Œ๋ฆฟ ์–ธ์–ด ๋˜๋Š” ๋ฌธ์ž์—ด ์ž‘์—…์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ์ž˜๋ชป๋œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. YAML๋„ ์ธ๊ฐ„ ์นœํ™”์ ์ด๊ธฐ ๋•Œ๋ฌธ์— YAML์— ๋Œ€ํ•ด ์ด๋ ‡๊ฒŒ ํ•˜๋Š” ์ด์œ ๋ฅผ ์•Œ ์ˆ˜ ์žˆ์ง€๋งŒ JSON์€ ์˜ˆ๋ฅผ ๋“ค์–ด Jinja ํ…œํ”Œ๋ฆฟ์ด ์•„๋‹ˆ๋ผ Python dict์—์„œ ์ƒ์„ฑ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

(๊ทธ๋Ÿฐ๋ฐ ์™œ ํ•˜๊ณ  ์‹ถ์€์ง€, ๋ฌด์—‡์„ ํ•˜๋ ค๊ณ  ํ•˜๋Š”์ง€ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค :p)

๊ทธ๊ฒŒ ๋ง์ด ๋˜๋Š” ๊ฒƒ ๊ฐ™์•„์š”. :-) ๋‚˜๋Š” #571์„ ๋‹ซ์„ ๊ฒƒ์ด๋‹ค.

JSON์€ Jinja์—์„œ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์ด ์ข‹์ง€ ์•Š์„ ์ˆ˜๋„ ์žˆ์ง€๋งŒ jinja๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ LaTeX๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด๋Ÿฐ ์ข…๋ฅ˜์˜ ๊ธฐ๋Šฅ์— ๋งค์šฐ ๊ด€์‹ฌ์ด ์žˆ์Šต๋‹ˆ๋‹ค. block_start_string ๋ฐ block_end_string ๋ฐ ๊ธฐํƒ€ Environment ๋ฅผ ์ˆ˜์ •ํ•˜์—ฌ ๋Œ€๋ถ€๋ถ„์˜ ๋ฐฉ๋ฒ•์„ ์–ป์—ˆ์Šต๋‹ˆ๋‹ค. ์ง€๊ธˆ์€ autoescape = False ๋ฅผ ์„ค์ •ํ–ˆ์ง€๋งŒ ์ด์ƒ์ ์œผ๋กœ๋Š” ์ž์‹ ์„ ํƒˆ์ถœํ•˜๊ธฐ ์œ„ํ•ด ๋ฌด์–ธ๊ฐ€๋ฅผ ์ „๋‹ฌํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค(์ •๊ทœ์‹์ฒ˜๋Ÿผ).

์ด๋Š” ์ผ๋ฐ˜ ํ…์ŠคํŠธ ๋ฐ ๋งˆํฌ๋‹ค์šด ์ƒ์„ฑ์—๋„ ์ ์šฉ๋ฉ๋‹ˆ๋‹ค. Jinja๋Š” ์ง€๊ธˆ๊นŒ์ง€ ๋น„-html ๋ฌธ์„œ๋ฅผ ํ…œํ”Œ๋ฆฟํ™”ํ•˜๋Š” ํ›Œ๋ฅญํ•œ ๋„๊ตฌ์˜€์Šต๋‹ˆ๋‹ค.

์—ฌ๋Ÿฌ ์กฐ๊ฑด๋ถ€ ์ฟผ๋ฆฌ ๋ถ€๋ถ„์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ str.format() ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ง€์ €๋ถ„ํ•ด์งˆ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— jinja๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ SQL ์ฟผ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ฐพ๊ณ  ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

์ด๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ, ์ฆ‰ ์‚ฌ์šฉ์ž ์ •์˜ ์ด์Šค์ผ€์ดํ”„ ๊ธฐ๋Šฅ๊ณผ jinjasql ์„ ํ—ˆ์šฉํ•˜๋Š” jinja-vanish ๊ฐ€ ์ด๋ฏธ ์žˆ์Šต๋‹ˆ๋‹ค.
์ฒซ ๋ฒˆ์งธ๋Š” ์ปดํŒŒ์ผ ์‹œ ์ƒ์ˆ˜ ํ‰๊ฐ€๋ฅผ ๋น„ํ™œ์„ฑํ™”ํ•ด์•ผ ํ•˜๋Š”๋ฐ, ์ด๋Š” ์•ฝ๊ฐ„ ์ข‹์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ํ•˜๋‚˜
ํ•„ํ„ฐ ์ ‘๊ทผ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ชจ๋“  ๋ณ€์ˆ˜ ํ‘œํ˜„์‹์— ๊ดœ์ฐฎ์ง€๋งŒ ์˜ณ์ง€ ์•Š๋‹ค๊ณ  ๋Š๋ผ๋Š” ํŠน์ˆ˜ ํ•„ํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

์ž์„ธํžˆ ๋“ค์—ฌ๋‹ค๋ณด์ง€๋Š” ์•Š์•˜์ง€๋งŒ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์€ ๊ทธ๋ฆฌ ์–ด๋ ต์ง€ ์•Š์€ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ๊ณ ๋ ค๋  ์ˆ˜ ์žˆ๊ฑฐ๋‚˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ๋ฒ”์œ„๋ฅผ ๋ฒ—์–ด๋‚ฌ์Šต๋‹ˆ๊นŒ?

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰