javascript 개요

  • javascript는 웹 개발에 쓰이는 프로그래밍 언어입니다. 초기 웹 브라우저의 시대가 열렸을 때 javascript만 작동할 수 있도록 표준이 생겼습니다. 그래서 python, java 등의 프로그래밍 언어는 브라우저에서 동작되지 않습니다.
  • 이 말은 웹 개발을 하기 위해서는 javascript를 필수적으로 알아야 합니다 (html, css도 화면을 디자인하기 위해 꼭 알아야 합니다)

💡 원래는 웹 브라우저에서 작동되는 프로그래밍 언어였지만 점점 인기가 많아져서 서버, 게임 개발 등 다양한 분야에서 사용되고 있습니다 우리가 다음에 배우게 될 서버, 모바일, 머신러닝 개발도 전부 javascript로 하게될 거예요!

 

크롬 브라우저의 개발자 도구 사용하기

브라우저를 통해서 개발자가 만든 html,css,javascript 기록을 볼 수 있습니다.

  1. 크롬 브라우저로 웹을 실행합니다.
  2. 맥 : Cmd + Option + I , 윈도우 Ctrl+ Shift + F12
  3. Elements 탭에서 HTML, CSS를 보고 수정할 수 있어요.
  4. Console 창에서 javascript 코드를 실행하고 결과를 볼 수 있어요!
  5. Network 창에서 브라우저가 네트워크 통신하는 내역들을 볼 수 있어요!

기본 로그 함수

브라우저 개발자 도구 → Console 창에서 로그를 확인할 수 있습니다.

console.log('인프런 수강생 여러분 환영합니다!!')

<aside> 💡 javascript에서는 코드 한 줄을 작성할 때, 맨 마지막에 ; 를 붙여줍니다. 안 붙여도 문제는 없으나 코드를 마무리한다는 암시를 가지고 있습니다.

</aside>

변수

변수는 데이터를 담는 공간입니다. 우리가 웹에서 보는 상품 정보, 이미지, ID 입력창 등은 전부 데이터를 바탕으로 보여지는 결과물입니다. 이때 데이터를 담는 변수는 기본 중의 기본입니다.

변수에 데이터를 넣어서 사용합니다.

선언과 정의

  1. 변수를 선언한다는 것은 어떤 변수를 사용할지 정하는 작업이예요. 변수를 선언할 때 javascript는 var, let, const 를 사용합니다.
  2. 변수를 정의하는 것은 선언된 변수에 값을 넣는 작업이에요.
var name;  //name이라는 변수를 선언한다.
name = "그랩"; //name이라고 선언된 변수에 "그랩"이라는 값을 저장한다.

var name = "그랩"; //합쳐서 이렇게 사용할 수 있어요.

//var, let, const 차이 
//1. var는 같은 이름의 변수를 다시 사용할 수 있어요. 요새는 var를 사용하지 않고 let, const만 사용하는 추세에요.
var num1 = 20;
var num1 = 'Bob';

//2. let은 한번 선언된 변수에 다시 새롭게 선언할 수 없어요. 
let num2 = 20;
num2 = "hello";
let num2 = 'Bob'; // <- 에러!

//3. const는 선언된 변수에 새로운 값을 정의할 수 없어요. 변수 값이 더이상 변경되지 않도록 할때 사용해요
const num3 = 30;
num3 = 'Bob'; // <- 에러!

[참고]

변수명은 영문 + 숫자로 지어야 하며 띄어쓰기와 특수문자가 불가능합니다.

변수 이름을 지을 때는 camelCase 혹은 snake_case 형태로 지으시는 걸 추천해요!

let first_name = 'bob' // snake case
let firstName = 'bob' // camel case

//변수명은 띄어쓰기와 특수문자가 불가능합니다.

자료형

자료형은 데이터의 종류를 의미합니다. 프로그래밍 세계에서 데이터는 각각의 타입을 가지고 있어요.

1. 기본 자료형 (Primitive Type)

javascript 뿐만 아니라 거의 모든 프로그래밍 언어에서 비슷하게 가지고 있는 **자료형(데이터 형식)**으로 string(문자), number(숫자), boolean(참/거짓 여부) 가 있습니다.

또한 javascript에서는 null과 undefined 자료형도 존재합니다.

null은 값이 없을 때 보통 사용하는 자료형입니다. undefined는 변수를 선언만 하고 정의하지 않은 상태일 때 들어가는 자료형입니다.

//-----------------------기본 자료형-------------------------

var name; //undefined
name = "그랩" //string (문자)
var age = 27; //number (숫자)
var isFool = false; //boolean (true/false)
var nully = null; //null 

[참고] 변수의 자료형을 확인하는 문법으로 typeof 가 있습니다.

console.log(typeof name) //string 출력

2. array(배열)

실제로 array는 object(객체)의 종류 중 하나로 object 자료형입니다.

array는 배열 혹은 리스트(List)라고 불립니다. 데이터를 순차적으로 담도록 도와줍니다.

<aside> 💡 메인 화면에 상품 정보들을 보여주기 위해선 상품 정보들이 순차적으로 들어가 있어야 합니다. productNames 배열안에 순차적으로 상품 이름을 넣는다고 생각해보세요!

</aside>

배열을 사용할 때는 [] Bracket을 사용합니다.

배열의 길이를 알고 싶으면? 배열.length 를 이용합니다.

배열 안에 값을 조회하려면? 배열**[순서 번호]** 로 접근합니다.

배열에 새로운 값을 추가하고 싶다면? 배열.push(값)을 이용합니다.

var productNames = ['농구공', '단백질 보충제'] //array 자료형 []
var productIds = [10,20]; //array 안에는 모든 자료형을 넣을 수 있습니다.
var productNestArray = [[0,1,2],[3,4,5]] //array안에 array도 가능하죠.

//productNames의 길이를 알고 싶다면? 
var length = productNames.length

//productNames의 첫번째 인자의 값에 접근하고 싶다면?
var firstValue = productNames[0]; //프로그래밍 세계에서 1번째는 숫자 0부터 시작해요.
var secondValue = productNames[1];

//productNames에 새로운 값을 추가하고 싶다면?
productNames[2] = '노션 글'; //array의 3번째에 값을 넣습니다. 선호하지는 않는 방식입니다.
articleNames.push('노션 글') //array의 마지막에 '노션 글' 값을 넣습니다. array에 값 추가할 때 선호하는 방식입니다.

<aside> 💡 일반적으로 javascript에서 변수 내부에 있는 무언가를 이용하려고 할 때
. 혹은 대괄호 [] 를 이용하게 됩니다.

앞으로 객체, 함수 등 많은 곳에서 내부에 있는 무언가에 접근할 때 사용될 거에요!

</aside>

3. 객체(object)

객체(object)는 자료들을 key, value형태로 저장하는 자료형이에요.

중괄호 {} 안에 key와 value를 순차적으로 넣습니다.

<aside> 💡 일반적으로 상품에는 제목, 가격, 설명 등의 데이터가 들어갑니다. product 객체 안에 title(제목), price(가격), description(설명)을 넣는다고 생각해보세요!

</aside>

//객체 형태
{ 
	key1 : value1,
	key2 : value2,
}

//실제 객체 사용
var product = {
    title: '농구공',
    description: '농구의 황제 조던이 사용했던 농구공입니다',
		price : 50000
}
var product = { 
    title: '농구공',
    description: '농구의 황제 조던이 사용했던 농구공입니다',
		price : 50000
}
// product의 name 값을 얻고 싶다면?
var productName = product['name']; //array에서 값을 가져오는 방식처럼 안에 key값을 넣습니다.
var productDescription = product.description //객체.key 로 접근할 수도 있습니다.

//product에 새로운 값을 추가, 변경하고 싶다면?
product['name'] = '축구공'; //값 변경1
product.name = '축구공'; //값 변경2
product['seller'] = '그랩'; //값 추가1
product.seller = '그랩'; //값 추가2

변수 Question

  1. object, array 자료형을 이용해서 3개의 상품이 들어가있는 배열(array)를 만들어보세요.
    • Answer
    • // 실제 서비스 응용 :: object + array var products = [{ name: '농구공', description: '농구 황제 마이클 조던이 사용한 농구공입니다', price: 100000, }, { name: '축구공', description: '축구 황제 메시가 사용한 축구공입니다', price: 50000 }, { name: '탁구공', description: '탁구 황제 그랩이 사용한 탁구공입니다', price: 500 }]
  2. 1번에서 만든 products 변수에서 2번째 상품의 name 값을 추출해 보세요.
    • Answer
    • products[1]['name'] products[1].name

연산자와 조건문

연산자

  • 연산자는 변수들(혹은 값)을 가공할 수 있도록 도와주는 친구에요.
  • 기본적으로 산술(덧셈 뺄셈)을 돕는 기본 연산자 , 값들을 비교하는 비교 연산자 , 논리적인 순서를 제공하는 논리 연산자 가 있습니다.

1. 기본 연산자

산술을 돕는 기본 연산자는 + , -, * , / 등이 있습니다.

  • 문자와 숫자를 더하면 문자가 됩니다.
//기본 연산자 (산술 연산자, 문자열 연산지)
var num1 = 5;
var num2 = 3;
var char1 = "가짜";
var char2 = "사나이"
var num3 = num1 + num2; //숫자 + 숫자 , 결과 : 8 
var char3 = char1 + " " + char2; //문자열 + 문자열 , 결과 : 가짜 사나이
var charNumMixed = char1 + num1; //문자열 + 숫자 , 결과 : 가짜5

2. 비교 연산자

값을 서로 비교하는 비교 연산자는 >, < , ≥ , ≤ , ===, !== 이 있습니다.

비교 연산자를 거치면 boolean 값을 반환 받습니다.

//비교연산자 (>, <, <=, >=, ===, !==)로 boolean 값을 반환합니다.
var name = '그랩';
var isFool = true;
var num = 100;

console.log(num < 5); //값의 크기를 비교, 결과 : false
console.log(name === '그랩'); //값이 일치하는 지를 비교, 결과 : true
console.log(name !== '홍길동'); //값이 일치하지 않는 지를 비교, 결과 : true

3. 부정 연산자

부정 연산자 !는 true와 false를 서로 변환시켜 줍니다.

//부정 연산자 !, true <-> false 로 반환해줍니다. 
var nope = false;
var yes = !nope  //true

4. 논리 연산자

논리 연산자는 다른 연산자들의 실행을 논리적으로 제어하는 연산자에요. 일반적으로 비교 연산자와 콤비로 많이 사용됩니다. 논리 연산자로 ||  && 가 있습니다.

&&는 통상적으로 AND 조건이라고 불러요. 앞의 연산 결과가 true일 때 뒤의 연산 값을 반환해요.

<aside> 💡 **그리고 라는 로직을 사용할 때 &&를 사용한다고 생각하시면 편해요**

</aside>

||는 통상적으로 OR 조건이라고 불러요. 앞의 연산 결과가 true라면 앞의 연산 값을 반환해요. false라면 뒤의 연산 값을 반환해요.

<aside> 💡 혹은 라는 로직을 사용할 때 ||를 사용한다고 생각하시면 편해요

</aside>

var name = "그랩";
var age = 27;

// &&는 앞의 연산 결과가 true일 때 뒤 연산을 수행함
console.log(name === '그랩' && age > 25); // 결과 : true
console.log(name === '그랩' && age > 30); // 결과 : false

// ||는 앞이 연산 결과가 true라면 뒤 연산을 실행하지 않음
console.log(name === '그랩' || age < 30) //결과 : true

// ||는 앞의 연산 결과가 false라면 뒤 연산을 수행함
console.log(name !== '그랩' || age > 25); //결과 : true

var nope = false; 
var yes = true; 
console.log(nope || yes); //결과 : true
console.log(nope && yes); //결과 : false

연산자 마스터 Question

var products = [{
    name: '농구공',
    description: '농구 황제 마이클 조던이 사용한 농구공입니다',
    price: 100000,
}, {
    name: '축구공',
    description: '축구 황제 메시가 사용한 축구공입니다',
    price: 50000
}]
  1. products의 길이가 1개 이상이면서 첫번째 상품 객체의 name이 '축구공' 인지를 확인하는 연산자를 작성하세요.products의 길이가 1개 **이상(≥)**인첫 번째 상품 객체의 name이 '축구공'인지**(===)** 확인하는 연산자
    • Answer
    • var result = products.length > 0 && products[0].name === '축구공'; console.log(result) //false 출력
  2. 동시에(AND)
  3. [HINT]

조건문

**조건문은 조건(Condition)에 따라서 로직을 다르게 수행하도록 돕습니다. 예를 들어 아래와 같이 조건에 따라 다른 로직을 수행할 때 전부 조건문이 사용됩니다.**

  1. 로그인을 한 사람에게는 프로필 이미지 보여준다. 아니라면 로그인 버튼을 보여준다
  2. 상품 정보들이 1개 이상이면 상품 화면들을 보여준다. 아니라면 상품 준비중이라는 화면을 보여준다.
if(조건){
	//로직
}

조건문은 기본적으로 if 가 사용됩니다. if의 안에 들어가는 값의 여부에 따라 로직의 수행 여부를 결정할 수 있습

니다.

  • true일 때는 로직을 수행함
  • false 혹은 null, 0, "", undefined일 때 로직을 수행하지 않음
var name = "그랩";
var age = 27;

//조건문 안에 true 혹은 특정 값이 들어있으면 내부 로직 수행함. (null, false, 0, "") 이면 수행X
if (name === "그랩") { //true가 들어있기에 수행함
    console.log("그랩 짱") 
}

if (age > 25) { //true가 들어있기에 수행함
    console.log("25살 이상")
}

if (name) { //값이 들어있기에 수행함
    console.log("이름에 문제 있어?")
}

var empty = "";
if (empty) { //빈 값은 false와 비슷한 의미. 수행하지 않음
    console.log('수행될까?')
}
  • if 문과 더불어 같이 사용되는 else if  else 가 있습니다. 값이 true이면 if 안의 로직이 수행되지만 만일 아닐 경우 else로 처리해줄 수 있습니다. 만약 3가지 이상의 로직이 각각 다른 상황에 처리되어야 한다면 else if 까지도 사용합니다.
var name = "그랩";
var age = 27;

//if else else if
if (age > 25 && name === '호연') { //값이 false이므로 'he is fake'이 출력됨
    console.log('he is real');
} else {
    console.log('he is fake');
}

if (age > 30) { //값이 false이므로 else if 로직으로 넘어감
    console.log('어느덧 30대인가');
} else if (age > 25) { //값이 true이므로 내부 로직이 실행됨
    console.log('아직 20대다');
} else { 
    console.log('철도 씹어먹을 나이');
}

조건문 마스터 Question

var products = [{
    name: '농구공',
    description: '농구 황제 마이클 조던이 사용한 농구공입니다',
    price: 100000,
}, {
    name: '축구공',
    description: '축구 황제 메시가 사용한 축구공입니다',
    price: 50000
}]
  1. products의 갯수가 1개 이상일 때와 아닐 때를 나누는 조건문을 짜보세요.
    • Answer
    • if (products.length > 0) { //아티클들 있는 화면 보여주기 } else { //빈 화면 보여주기 }
  2. products의 갯수가 5개 이상일 때, 1~4개 사이일 때, 0개일 때 조건문을 짜보세요.
    • Answer
    • if (products.length >= 5) { //1번 로직 } else if(products.length >= 1){ //2번 로직 } else{ //3번 로직 }

함수

함수의 기본

**함수는 자바스크립트의 꽃이라고 불릴 정도로 정말 많이 사용됩니다.** 함수는 작업을 수행하는 코드들을 정의하는 코드 블록입니다.

함수도 변수와 마찬가지로 선언한 후 사용하면 됩니다. 다만 방식이 조금 다를 뿐입니다.

함수를 선언하는 방식은 크게 2종류로 선언식  표현식 이 있습니다 (둘의 차이에 대해서는 교육 과정 밖이라서 검색해보심을 권장합니다)

//sayHello라는 함수를 선언하기 

//첫 번째 방식 - 함수 선언식이라고 함
function sayHello(){ 
	console.log("say Hello!");
}

//두 번째 방식 - 함수 표현식이라고 함
const sayHello = function (){
	console.log("say Hello!");	
}

함수를 사용한다는 것은 실행한다는 것을 뜻합니다. 실행할 때 소괄호 ()를 붙입니다. 실행되면 함수의 {} 안에 있는 코드들이 실행됩니다.

//선언된 sayHello 함수를 사용한다.
sayHello(); //say Hello! 가 출력됨

함수를 선언한(만든) 후 사용하면 됩니다. 함수는 한 번 만들어 두면 재사용이 가능하기에 코드를 깔끔하게 관리할 수도 있습니다.

함수 인자

함수의 ()내부에 입력 값을 넣을 수도 있습니다. 이를 인자 혹은 파라미터 라고 합니다. 함수의 인자를 활용하면 함수를 더 확장성 있게 사용이 가능합니다.

우리가 수학 시간에 배운 f(x) = 3x +5를 생각해보면 그 안에 값을 넣어서 계산을 하잖아요? 프로그래밍도 비슷합니다.

  • 함수의 인자명은 문자+숫자 형태로 자유롭게 적을 수 있습니다.
function calculate(x) { //여기서 x를 파라미터(입력값)라고 
	var result = 3 * x + 5;
	console.log('결과 값은 '+result+'입니다');
}
var result = calculate(5); //결과 값은 20입니다.
     
var getAge = function(name, age) { //파라미터는 여러 개 넣어도 됩니다.
   console.log(name + '은 ' + age + '살입니다.');
}
getAge('그랩',27); //그랩은 27살입니다.

함수 값 반환(return)

이제 마지막! 함수는 값을 반환할 수도 있습니다.

return이라는 표현을 통해서 값을 반할 수 있는데요. 여기서 값은 모든 자료형(string, number, 배열, 객체) 그리고 함수 또한 return이 가능합니다.

		 function calculate(x) { //함수를 실행했을 때 return이 있어야지만 값을 얻을 수 있다. 
        var result = 3 * x + 5;
				return result;
     }
     var value1 = calculate(5); //calculate를 호출하면 20의 결과값을 반환합니다.
     var value2 = calculate(10); //calculate를 호출하면 35의 결과값을 반환합니다.
		 console.log(value1);
		 console.log(value2);
		 
		 //입력한 파라미터를 profile 객체로 만들어주는 함수			
     function getProfile(profile_name, profile_age) { 
				return { //여기선 객체를 return해요.
					name : profile_name,
					age : profile_age
				}
     }
		 var profile = getProfile('래리',27); //name, age를 key로 가지는 객체를 받습니다.
		 console.log(profile.name) //래리가 출력된다.

*** 함수에서 return을 하게 되면 return 아래에 있는 코드는 실행되지 않습니다. return은 함수를 종료시키는 구문이기도 합니다.**

function sayHello(){
	console.log('실행 O');
	return;
	console.log('실행 X'); //return 아래에 있는 코드는 실행되지 않음
}

sayHello(); 

함수에서 주의할 점

  1. 일반적으로 함수 안에 선언된 변수는 밖에서 사용이 불가능합니다.
function sayHello(){
	var name = "그랩";
}
console.log(name) //undefined가 출력됨
  1. 반면 함수 밖에서 선언된 변수는 함수 {} 안에서 사용이 가능합니다.
var name = "민수"
function getName(){ 
//여기서 사용되는 name은 함수의 인자인 name입니다. 만약 함수의 인자가 name이 아니라면 위의 변수 name을 가르킵니다.
	console.log(name);
}

getName() //래리가 출력됩니다.

{} 를 기준으로 밖에 있는 변수는 안에서도 사용이 가능하다고 생각하시면 좋습니다. if문에서도 {}가 사용되므로 마찬가지입니다.

함수 마스터 Question

var products = [{
    name: '농구공',
    description: '농구 황제 마이클 조던이 사용한 농구공입니다',
    price: 100000,
		seller: '민수'
}, {
    name: '축구공',
    description: '축구 황제 메시가 사용한 축구공입니다',
    price: 50000,
		seller: '철수'
}]
  1. 인자로 배열을 받았을 때 길이를 return 하는 함수를 만드시오. 그리고 products를 넣어 실행해보세요.
    • Answer
    • function getProductLength(arr){ return arr.length; } getProductLength(products) //2가 반환됨
  2. product 객체를 넣었을 때 product의 seller를 반환하는 함수를 만들어 보세요. 그리고 products의 첫번째 값을 넣어 실행해보세요.
    • Answer
    • //product에는 객체가 들어간다고 가정하고 함수를 만듬 function getProductSeller(product){ //product의 객체 안에는 seller가 있으므로 이를 접근해서 반환시킴 return product.seller; } getProductSeller(products[0]); //민수가 반환됨

반복문

  • 반복문 은 말 그대로 적혀진 코드를 반복적으로 실행시켜 줍니다.

<aside> 💡 예를 들어 상품 화면에서 상품 정보들을 100개 보여준다고 했을 때 상품 정보를 보여주는 코드를 100번 짜야할까요? 이런 상황에서 한 번의 코드만 짜고 반복문을 이용하면 더 효과적이겠죠.

</aside>

기본 문법은 아래와 같습니다.

첫 번째 구문 :  처음 변수를 선언합니다. 두 번째 구문 :  해당 연산 결과가 false가 될 때까지 짠 코드를 반복시킵니다. 세 번째 구문 : i를 1씩 증가시키는 구문입니다.

// 기본 반복문
// 첫번 째 변수를 선언한 후
// 두번 째 조건이 false가 되기 전까지 코드를 실행해라
// 세번 째 i++ 는 i를 1씩 더해라
for(var i = 0; i < 10; i++){
	console.log("나는 그랩이다"); //총 10번 호출이 됩니다.
}

  • 주의 : 마지막 ++ 구문에는 ;를 붙이지 않습니다.

for문에서 사용되는 변수 i는 안에서 사용이 가능합니다. 보통 안에 코드가 실행될 때 몇 번째 호출되고 있는지 알기 위해 사용합니다.

for (var i = 0; i < 10; i++) {
    var text = (i+1) + '번째 호출입니다'; //i는 0부터 9까지 순차적으로 들어가게 됩니다.
    console.log(text);
}

보통 반복문은 Array와 찰떡 궁합입니다. Array 안에 있는 요소들을 전부 조회할 때 반복문을 사용하면 손쉽게 조회할 수 있습니다.

//Array를 활용한 반복문
var products = ['농구공', '축구공'];
for (var i = 0; i < products.length; i++) {
    var name = products[i]; //i는 0, 1이 차레대로 들어갑니다. array의 1번째, 2번째 값을 가져옵니다.
		console.log(name); 
}
  • 심화학습
    articles.forEach(function (article, index) { //첫번째 파라미터에는 값, 두번째 파라미터에는 순서(index)가 들어간다.
             console.log((index + 1) + '번째 호출');
             console.log(article);
    })
    articles.map((article, index) => { //map함수는 return을 사용할 수 있다.
         console.log((index + 1) + '번째 호출');
         return article.name;
    });
    var articleNames = articles.map((article, index) => { //articleNames은 각 article들의 name이 들어간 배열이다
         console.log((index + 1) + '번째 호출');
         return article.name;
    });
    
    var articleElements = articles.map((article,index) =>{ //React에서는 다음과 같은 방식으로 데이터가 담긴 배열을 화면에 표시합니다.
    	return (
    		<div>
    			<span>{article.name}</span>
    			...
    		</div>
    	)
    })
    
  • 반복문과 찰떡인 자료형은 바로 배열입니다. 배열의 값들을 순차적으로 조회하기 위해 반복문이 굉장히 많이 사용됩니다. 이 때 배열을 반복시키는 함수로 forEach  map 이 있습니다.

반복문 마스터 Question

var products = [{
    name: '농구공',
    description: '농구 황제 마이클 조던이 사용한 농구공입니다',
    price: 100000,
		seller: '민수'
}, {
    name: '축구공',
    description: '축구 황제 메시가 사용한 축구공입니다',
    price: 50000,
		seller: '철수'
}]
  1. products 배열을 넣었을 때, 그 안에 가격(price)를 순서대로 출력(console.log)하는 함수를 만들어보세요.
    • Answer
    • function getProductsPrice(arr){ for(var i = 0; i < arr.length ;i++){ console.log(arr[i].price); } } getProductsPrice(products);

javascript 최종 문제

조건문, 반복문, 함수를 조합해서 문제를 해결해봅시다!

var allProducts = [{
    name: '농구공',
    description: '농구 황제 마이클 조던이 사용한 농구공입니다',
    price: 100000,
}, {
    name: '축구공',
    description: '축구 황제 메시가 사용한 축구공입니다',
    price: 50000
}, {
    name: '야구공',
    description: '박찬호가 던졌던 야구공입니다.',
    price: 75000
}]

products 배열을 넣었을 때, 가격이 60000원 이상인 product 객체를 담은 배열 반환하는 함수를 만들어라.

//Hint
function ~
	var newProducts = [];
	for ~
		if ~
	return ~
  • Answer

 

+ Recent posts