본문 바로가기

Contact 日本語 English

【웹 프로그래밍】 HTML 앱 라이브러리

 

HTML 앱 라이브러리(HTMP app library)

 

추천글 : 【컴퓨터과학】 컴퓨터과학 목차, 【웹 프로그래밍】 HTML 


1. HTML로 Linux rsync, SCP 코드 생성하기 [본문]

2. 구글 애드센스 Rage Click 방지하기 [본문]

3. CellMarker 2.0: HTML interactive table 만들기 [본문]

4. 웹페이지에서 텍스트 입력 시 DB에서 데이터 호출 구현 [본문]

5. AlphaFold2를 통한 단백질 라이브러리 구축 [본문]

6. 히포크라테스 기질테스트 프로그램과 12기질 장단점 [본문]

7. HTML로 Word Counter 만들기 [본문]

8. USD to KRW 환율 디스플레이 [본문]

9. 현재 포스팅 내 서치 엔진 [본문]

10. 말풍선 [본문]

11. 10진수와 16진수 상호 간 변환 [본문]

12. KST, PST, CST, EST 상호 간 변환 [본문]

13. 단순 Tic-Tac-Toe 게임 [본문]

14. meter-feet, kg-pound, 섭씨-화씨 상호 간 변환 [본문]


※ Sigil 전자책 제작 프로그램이나 반응형 앱에서 유용하게 사용할 수 있음

 

1. HTML로 Linux rsync, SCP 코드 생성하기 [목차]

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>File Transfer Command Generator</title>
</head>
<body>

<h2>File Transfer Command Generator</h2>

<form id="transferForm">
    <label for="srcFile">Source File Address (e.g., ~/Downloads/test.txt):</label>
    <input type="text" id="srcFile" name="srcFile" required><br><br>

    <label for="destIP">Destination IP Address:</label>
    <input type="text" id="destIP" name="destIP" required><br><br>

    <label for="port">Port:</label>
    <input type="number" id="port" name="port" required><br><br>

    <label for="id">ID (username on the remote machine):</label>
    <input type="text" id="id" name="id" required><br><br>

    <label for="destPath">Destination File Path (e.g., ~/DATA1/):</label>
    <input type="text" id="destPath" name="destPath" required><br><br>

    <input type="button" value="Generate rsync command" onclick="generateCommand('rsync')">
    <input type="button" value="Generate scp command" onclick="generateCommand('scp')"><br><br>

    <textarea id="outputCommand" rows="4" cols="50" readonly></textarea>
</form>

<script>
    function generateCommand(method) {
        const srcFile = document.getElementById('srcFile').value;
        const destIP = document.getElementById('destIP').value;
        const port = document.getElementById('port').value;
        const id = document.getElementById('id').value;
        const destPath = document.getElementById('destPath').value;

        let command = "";

        if (method === "rsync") {
            command = `rsync -avz -e 'ssh -p ${port}' ${srcFile} ${id}@${destIP}:${destPath}`;
        } else if (method === "scp") {
            command = `scp -P ${port} ${srcFile} ${id}@${destIP}:${destPath}`;
        }

        document.getElementById('outputCommand').value = command;
    }
</script>

</body>
</html>

 

File Transfer Command Generator

File Transfer Command Generator













 

 

2. 구글 애드센스 Rage Click 방지하기 [목차]

⑴ 목적

필요성 1. 정상적인 rage click이라고 하더라도 구글 애드센스의 수익성을 떨어트림 

○ 해당 무효 클릭 자체의 수익은 당연히 무효가 됨 

○ 다른 광고의 품질에 영향을 줌 

필요성 2. 의도적으로 rage click을 일으켜서 광고 게시자의 애드센스 계정을 정지시키는 사례가 발견 

⑵ 방법

1단계. 구글 애드센스 각각에 id를 부여 : data-ad-client 및 data-ad-slot을 확인한 뒤 id 부분을 적절하게 할당 

 

#before
<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<ins class="adsbygoogle"
     style="display:block"
     data-ad-format="fluid"
     data-ad-layout-key="-eo+u+3m-ue+16q"
     data-ad-client="ca-pub-######"
     data-ad-slot="######"></ins>
<script>
     (adsbygoogle = window.adsbygoogle || []).push({});
</script>


#after
<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<ins class="adsbygoogle"
     style="display:block"
     data-ad-format="fluid"
     data-ad-layout-key="-eo+u+3m-ue+16q"
     data-ad-client="ca-pub-######"
     data-ad-slot="######"
		 id="my_id"></ins>
<script>
     (adsbygoogle = window.adsbygoogle || []).push({});
</script>

 

2단계. 아래 코드를 <head> ~ </head> 사이에 삽입

 

<script>
function preventRageClicks(elementId) {
  // your ad element
  let adElement = document.getElementById(elementId); 

  let clickCount = 0;
  let lastClicked = 0;
  let delay = 3000; // time in milliseconds

  adElement.addEventListener('click', function (e) {
    let timeNow = new Date().getTime();

    if (timeNow - lastClicked < delay) {
      clickCount += 1;
    } else {
      clickCount = 0;
    }

    if (clickCount > 1) {
      e.preventDefault(); // prevents the default action i.e., stops the click event.
      adElement.style.pointerEvents = "none"; // disable clicks

      setTimeout(function () { 
        adElement.style.pointerEvents = "auto"; // enable clicks after delay
      }, delay);
    }

    lastClicked = timeNow;
  });
}

preventRageClicks('my_id'); 
<!-- If you have another id, just add it here -->
<!-- preventRageClicks('my_another_id'); -->
</script>

 

⑶ 해석

① clickCount 업데이트 정책

○ my_id를 가진 어떤 광고가 마지막 클릭 이후 delay (3초) 이내에 클릭되면 clickCount가 +1이 됨 

○ my_id를 가진 어떤 광고가 마지막 클릭 이후 delay (3초) 이후에 클릭되면 clickCount는 0이 됨 

② 만약 clickCount가 2가 되면 (즉, 총 3번을 빠르게 클릭하면) click을 비활성화

○ clickCount 역치값은 사용자 유입이 많아지면 적당히 상향 조절해야 할 것으로 보임 

③ 그 뒤 delay (3초)의 시간이 되면 다시 click을 활성화

 

 

3. CellMarker 2.0: HTML interactive table 만들기 [목차]

⑴ 개요

목적 1. 셀 타입 마커 유전자CellMarker 2.0 정보를 반영

목적 2. 티스토리 HTML 편집창을 이용하여 interactive table을 만들 수 있음을 증명 (PoC 성격)

목적 3. ChatGPT 4.0을 이용하여 html 및 javascript 코딩 역량을 실질적으로 확장하기 위함 

⑵ 프로젝트

① 타겟 데이터셋 (ref)

 

Cell_marker_All.csv
8.74MB

 

② 코드

 

<!DOCTYPE html>
<html>
<head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/PapaParse/5.3.0/papaparse.min.js"></script>
    <style>
        #csv-table {
            border-collapse: collapse;
            width: 100%;
        }
        #csv-table td {
            border: 1px solid #ddd;
            padding: 8px;
        }
        #csv-table tr:nth-child(even) {
            background-color: #f2f2f2;
        }
        #csv-table tr:hover {
            background-color: #ddd;
        }
    </style>
</head>
<body>
    <input type="text" id="filter" placeholder="Filter table...">
    <table id="csv-table"></table>

    <script>
        $(document).ready(function(){
            var fullData = []; // We will store the full data set here

            Papa.parse('https://blog.kakaocdn.net/dn/qnnYk/btsmscriEvQ/fStKJosLyfL0zl0j0qy6E0/Cell_marker_All.csv?attach=1&knm=tfile.csv', {
                download: true,
                header: true,
                complete: function(results) {
                    fullData = results.data; // Store the full data set
                    updateTable(fullData.slice(0, 5)); // Initially show the first 5 rows
                }
            });

            // This function updates the table with the given data
            function updateTable(data) {
                var table = $('#csv-table');
                table.empty(); // Clear the table before adding new rows
                $.each(data, function(index, value){
                    var row = $('<tr></tr>');
                    $.each(value, function(key, val){
                        $(row).append('<td>'+val+'</td>');
                    });
                    $(table).append(row);
                });
            }

            // This function filters the data based on the given query and updates the table
            function filterTable(query) {
                var filteredData = fullData.filter(function(row) {
                    return Object.values(row).some(function(val) {
                        return String(val).includes(query);
                    });
                });
                updateTable(filteredData.slice(0, Math.min(5, filteredData.length))); // Show only the first 5 rows of the filtered data
            }

            // Listen for input events on the filter field
            $('#filter').on('input', function() {
                filterTable($(this).val()); // Filter the table whenever the input changes
            });
        });
    </script>
</body>
</html>

 

○ 첫 5개만 표시되도록 함 

○ 필터 부분에 타이핑을 하면 그 타이핑을 적어도 부분적으로 포함하는 행들이 출력됨

○ 필터 부분의 타이핑은 대소문자를 구분함 (case-sensitive)

○ 표는 줄무늬 디자인 

○ 마우스 커서를 갖다 대면 색이 변함 

③ HTML interactive table 예시 

 

 

 

4. 웹페이지에서 텍스트 입력 시 DB에서 데이터 호출 구현 [목차]

⑴ 개요

① 목표 : AlphaFold2 데이터베이스 같은 방대한 데이터베이스를 포스팅에 적극적으로 활용

② 전략 : GitHub, NAS, 구글 드라이브, 원 드라이브, 기타 데이터 서버 등에 구축된 데이터베이스를 웹페이지에서 시각화하는 방안

③ 그 중 GitHub를 선택한 이유

○ GitHub는 파일 디렉토리와 유사한 형태로서 예측 가능한 url을 생성해줌

○ 예를 들어, '0'에 대응하는 파일은 https://github.com/JB243/nate9389/blob/main/Javascript/data/0.png에 저장돼 있음

⑵ 플러그인

① html 코드 

 

<html>
<head>
</head>
<body>
<script language="javascript">
function printName(){
  var result = 'https://github.com/JB243/nate9389/blob/main/Javascript/data/' + document.getElementById('name').value + '.png?raw=true';
  document.getElementById("imgId").src = result
}
</script>

<form>
<div>
<label for="uname">Choose a character or a number: </label>
<input type = "text" id="name" name="name" onkeyup='printName()' required size="45" />
<span class="validity"></span>
</div>
</form>
<img id="imgId" src="">

</body>
</html>

 

② 구현 결과 : 다음 입력칸에 영문 소문자, 영문 대문자, 숫자, 특수기호, 혹은 한글자모 입력해보기

 

 

③ 레퍼런스 (ref1, ref2, ref3)

 

 

5. AlphaFold2를 통한 단백질 라이브러리 구축 [목차]

 

 

6. 히포크라테스 기질테스트 프로그램과 12기질 장단점 [목차]

 

 

7. HTML로 Word Counter 만들기 [목차]

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Word and Character Counter</title>
    <script>
        function updateCounters() {
            let text = document.getElementById('textInput').value;
            
            // Count words
            let words = text.split(/\s+/).filter(function(word) {
                return word.length > 0;
            });
            document.getElementById('wordCount').innerText = words.length;

            // Count characters
            let characters = text.length;
            document.getElementById('characterCount').innerText = characters;
        }
    </script>
</head>
<body>
    <h2>Word and Character Counter</h2>
    <textarea id="textInput" oninput="updateCounters()" placeholder="Type your text here..." rows="10" cols="50"></textarea>
    <div>
        Word Count: <span id="wordCount">0</span>
    </div>
    <div>
        Character Count: <span id="characterCount">0</span>
    </div>
</body>
</html>

 

Word and Character Counter

Word and Character Counter

Word Count: 0
Character Count: 0

 

 

8. USD to KRW 환율 디스플레이 [목차]

 

<!DOCTYPE html>
<html>
<head>
    <title>USD to KRW Conversion</title>
    <script>
        // Function to fetch conversion rate and display it
        function getConversionRate() {
            fetch('https://api.exchangerate-api.com/v4/latest/USD')
            .then(response => response.json())
            .then(data => {
                const rate = data.rates.KRW;
                document.getElementById('conversionRate').innerHTML = `1 USD = ${rate.toFixed(2)} KRW`;
            })
            .catch(error => console.error('Error:', error));
        }
    </script>
</head>
<body onload="getConversionRate()">
    <h2>USD to KRW Conversion Rate</h2>
    <p id="conversionRate">Loading...</p>
</body>
</html>

 

USD to KRW Conversion

USD to KRW Conversion Rate

Loading...

 

 

9. 현재 포스팅 내 서치 엔진 [목차]

 

<!DOCTYPE html>
<html>
<head>
    <title>Local Page Search</title>
</head>
<body>
    <h2>Enter Sentence to Find Matching Paragraph</h2>
    <form id="searchForm">
        <label for="sentence">Sentence:</label><br>
        <input type="text" id="sentence" name="sentence" required><br><br>
        <input type="submit" value="Search">
    </form>
	<br>
    <div id="result"></div>

    <script>
        document.getElementById('searchForm').addEventListener('submit', function(e) {
            e.preventDefault();

            var sentence = document.getElementById('sentence').value.toLowerCase();
            var paragraphs = document.querySelectorAll('p');
            var found = false;

            for (var i = 0; i < paragraphs.length; i++) {
                if (paragraphs[i].textContent.toLowerCase().includes(sentence)) {
                    document.getElementById('result').innerHTML = 'Matching paragraph: ' + paragraphs[i].outerHTML;
                    found = true;
                    break;
                }
            }

            if (!found) {
                document.getElementById('result').innerText = 'No matching paragraph found';
            }
        });
    </script>
</body>
</html>

 

Local Page Search

Enter Sentence to Find Matching Paragraph





 

 

10. 말풍선 [목차]

 

<!DOCTYPE html>
<html>
<head>
<style>
.bubble {
    position: relative;
    display: inline-block;
    padding: 10px 20px;
    border-radius: 30px;
    color: black;
}

.pink-bubble {
    background: linear-gradient(to right, #FFD1DC, #FFB6C1); /* lighter pink gradient */
}

.blue-bubble {
    background: linear-gradient(to right, #ADD8E6, #87CEFA); /* lighter blue gradient */
}

.bubble::after {
    content: '';
    position: absolute;
    border: 10px solid transparent;
}

.pink-bubble::after {
    border-top-color: #FFD1DC; /* light pink */
}

.blue-bubble::after {
    border-top-color: #ADD8E6; /* light blue */
}

/* Positioning the triangle */
.bubble::after {
    top: 100%;
    left: 20px;
}

</style>
</head>
<body>

<div class="bubble pink-bubble">Hello, I'm a pink bubble!</div>
<div class="bubble blue-bubble">And I'm a blue bubble!</div>

</body>
</html>

 

Hello, I'm a pink bubble!
And I'm a blue bubble!

 

 

 

11. 10진수와 16진수 상호 간 변환 [목차]

 

<!DOCTYPE html>
<html>
<head>
    <title>DEC to HEX and HEX to DEC Converter</title>
</head>
<body>

<h2>DEC to HEX and HEX to DEC Converter</h2>

<!-- Input for DEC to HEX conversion -->
<div>
    <label for="decInput">Enter Decimal:</label>
    <input type="number" id="decInput" />
    <button onclick="convertDecToHex()">Convert to HEX</button>
</div>
<p id="decToHexResult"></p>

<!-- Input for HEX to DEC conversion -->
<div>
    <label for="hexInput">Enter Hexadecimal:</label>
    <input type="text" id="hexInput" />
    <button onclick="convertHexToDec()">Convert to DEC</button>
</div>
<p id="hexToDecResult"></p>

<script>
    // Function to convert DEC to HEX
    function convertDecToHex() {
        var decValue = document.getElementById('decInput').value;
        var hexValue = parseInt(decValue).toString(16).toUpperCase();
        document.getElementById('decToHexResult').innerHTML = "Hexadecimal: " + hexValue;
    }

    // Function to convert HEX to DEC
    function convertHexToDec() {
        var hexValue = document.getElementById('hexInput').value;
        var decValue = parseInt(hexValue, 16);
        document.getElementById('hexToDecResult').innerHTML = "Decimal: " + decValue;
    }
</script>

</body>
</html>
DEC to HEX and HEX to DEC Converter

DEC to HEX and HEX to DEC Converter

 

 

12. KST, PST, CST, EST 상호 간 변환 [목차]

⑴ Daylight Saving Time (DST) (e.g., EST → EDT, CST → CDT, PST → PDT)

① 낮이 긴 봄, 여름에 1시간씩 일찍 일과를 시작하기 위함

② 북미 지역(e.g., 미국, 캐나다)에서 보통 3월 2번째 일요일 ~ 11월 1번째 일요일까지 적용됨

⑵ 코드 구현 

 

<!DOCTYPE html>
<html>
<head>
    <title>Time Zone Converter</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.34/moment-timezone-with-data.min.js"></script>
</head>
<body>
    <div style="font-family: Arial, sans-serif; max-width: 600px; margin: 20px auto; padding: 20px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);">
        <h2 style="text-align: center;">Time Zone Converter</h2>
        <div style="margin-bottom: 20px;">
            <label for="sourceTime">Enter Time (YYYY-MM-DD HH:mm):</label>
            <!-- <input type="text" id="sourceTime" value="2024-02-17 10:00" style="width: 100%; padding: 8px; margin-top: 5px;"> -->
            <input type="text" id="sourceTime" style="width: 100%; padding: 8px; margin-top: 5px;">
        </div>
        <div style="margin-bottom: 20px;">
            <label for="sourceZone">Source Time Zone:</label>
            <select id="sourceZone" style="width: 100%; padding: 8px; margin-top: 5px;">
                <option value="Asia/Seoul">KST</option>
                <option value="America/Los_Angeles">PST</option>
                <option value="America/Chicago">CST</option>
                <option value="America/New_York">EST</option>
            </select>
        </div>
        <div style="margin-bottom: 20px;">
            <label for="targetZone">Target Time Zone:</label>
            <select id="targetZone" style="width: 100%; padding: 8px; margin-top: 5px;">
                <option value="Asia/Seoul">KST</option>
                <option value="America/Los_Angeles">PST</option>
                <option value="America/Chicago">CST</option>
                <option value="America/New_York">EST</option>
            </select>
        </div>
        <button onclick="convertTime()" style="width: 100%; padding: 10px; background-color: #007bff; color: white; border: none; cursor: pointer;">Convert</button>
        <p id="resultTime" style="margin-top: 20px;"></p>
    </div>

    <script>
    function convertTime() {
        const sourceTimeValue = document.getElementById('sourceTime').value;
        const sourceZoneSelect = document.getElementById('sourceZone');
        const targetZoneSelect = document.getElementById('targetZone');
        const sourceZone = sourceZoneSelect.options[sourceZoneSelect.selectedIndex].value;
        const targetZone = targetZoneSelect.options[targetZoneSelect.selectedIndex].value;

        // Using moment-timezone to parse the input time in the source time zone
        const sourceTimeMoment = moment.tz(sourceTimeValue, "YYYY-MM-DD HH:mm", sourceZone);

        // Then, converting to the target time zone
        const convertedTime = sourceTimeMoment.tz(targetZone).format('dddd, MMM D, YYYY, hh:mm A z');

        // Display the result
        document.getElementById('resultTime').innerText = "Converted Time: " + convertedTime;
    }
    
    document.addEventListener('DOMContentLoaded', function() {
        var currentDateTime = moment().format('YYYY-MM-DD HH:mm');
        document.getElementById('sourceTime').value = currentDateTime;
    });
</script>

</body>
</html>

 

Time Zone Converter

Time Zone Converter

 

 

13. 단순 Tic-Tac-Toe 게임 (ref) [목차]

 

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tic Tac Toe Game</title>
<style>
  .grid {
    display: grid;
    grid-template-columns: repeat(3, 100px);
    grid-gap: 5px;
    margin: 20px auto;
  }
  .cell {
    width: 100px;
    height: 100px;
    background-color: #f0f0f0;
    display: flex;
    justify-content: center;
    align-items: center;
    font-size: 24px;
    cursor: pointer;
  }
</style>
</head>
<body>

<div id="game" class="grid"></div>

<script>
const playerX = 'X';
const playerO = 'O';
let currentPlayer = playerX;

// Initialize the game board
const gameBoard = Array(9).fill(null);

// Function to create the game grid
const createGrid = () => {
  const gameElement = document.getElementById('game');
  gameBoard.forEach((cell, index) => {
    const cellElement = document.createElement('div');
    cellElement.id = index;
    cellElement.className = 'cell';
    cellElement.addEventListener('click', cellClick, { once: true });
    gameElement.appendChild(cellElement);
  });
};

// Handle cell click
function cellClick(event) {
  const cellIndex = event.target.id;
  if (!gameBoard[cellIndex]) {
    gameBoard[cellIndex] = currentPlayer;
    event.target.innerText = currentPlayer;

    if (checkWinner(currentPlayer)) {
      alert(`${currentPlayer} wins!`);
      resetGame();
      return; // Stop further execution
    } else if (gameBoard.every(cell => cell !== null)) {
      alert("It's a tie!");
      resetGame();
      return; // Stop further execution
    }
    currentPlayer = currentPlayer === playerX ? playerO : playerX;
  }
}

// Check for a winner
function checkWinner(player) {
  const winningCombinations = [
    [0, 1, 2],
    [3, 4, 5],
    [6, 7, 8],
    [0, 3, 6],
    [1, 4, 7],
    [2, 5, 8],
    [0, 4, 8],
    [2, 4, 6],
  ];

  return winningCombinations.some(combination => {
    return combination.every(index => {
      return gameBoard[index] === player;
    });
  });
}

// Reset the game
function resetGame() {
  setTimeout(() => {
    document.getElementById('game').innerHTML = '';
    gameBoard.fill(null);
    createGrid();
    currentPlayer = playerX;
  }, 1000);
}

createGrid();
</script>

</body>
</html>

 

Tic Tac Toe Game

 

 

14. meter-feet, kg-pound, 섭씨-화씨 상호 간 변환 [목차]

 

<!DOCTYPE html>
<html>
<head>
    <title>Conversion Tool</title>
</head>
<body>
    <h1>Conversion Tool</h1>

    <label for="conversionType">Choose a conversion type:</label>
    <select id="conversionType">
        <option value="metersToFeet">Meters to Feet</option>
        <option value="feetToMeters">Feet to Meters</option>
        <option value="kilogramsToPounds">Kilograms to Pounds</option>
        <option value="poundsToKilograms">Pounds to Kilograms</option>
        <option value="celsiusToFahrenheit">Celsius to Fahrenheit</option>
        <option value="fahrenheitToCelsius">Fahrenheit to Celsius</option>
    </select>

    <br><br>

    <label for="inputValue">Enter value:</label>
    <input type="number" id="inputValue" placeholder="Enter value">

    <button onclick="convert()">Convert</button>

    <h2 id="result">Converted value: </h2>

    <script>
        function convert() {
            var conversionType = document.getElementById("conversionType").value;
            var value = parseFloat(document.getElementById("inputValue").value);
            var result = 0;

            if (!value) {
                document.getElementById("result").innerText = "Please enter a valid number";
                return;
            }

            if (conversionType === "metersToFeet") {
                result = value * 3.28084;
            } else if (conversionType === "feetToMeters") {
                result = value / 3.28084;
            } else if (conversionType === "kilogramsToPounds") {
                result = value * 2.20462;
            } else if (conversionType === "poundsToKilograms") {
                result = value / 2.20462;
            } else if (conversionType === "celsiusToFahrenheit") {
                result = (value * 9/5) + 32;
            } else if (conversionType === "fahrenheitToCelsius") {
                result = (value - 32) * 5/9;
            }

            document.getElementById("result").innerText = "Converted value: " + result.toFixed(2);
        }
    </script>
</body>
</html>

 

Conversion Tool App

Conversion Tool App



Converted value:

 

입력: 2023.08.24 09:23

수정: 2023.12.04 13:28