프로그래밍 언어론

Jan 26, 2024
프로그래밍 언어론
 
 
기말범위: 교재 4장~15장
  1. 프로그래밍 언어 소개
  1. 프로그래밍 언어의 발전 과정 및 동작원리
    1. 1. 저장 프로그램 방식의 에드박이 등장하면서 프로그램이라는 개념이 등장하게 되었다.
      2. 1950년대 초기 프로그래밍 언어로 Fortran은 수식 계산, 변수, 대입문, 함수, 제어문의 초기 형태를, Algol은 제어 구조 개념을, LISP는 함수형 언어 개념을 소개하였다.
      3. 1960년대 발표된 Cobol은 레코드를 통한 자료 구조 개념을 제시하였다. BASIC은 교육용 언어로서 큰 인기를 끌었으며 Simula는 객체지향 개념을 처음 소개하였다.
      4. 1970년대 가장 영향력이 높은 프로그래밍 언어는 C이다. Pascal은 구조화 프로그래밍의 교육용 언어로 자리잡았고, 그 외 다양한 패러다임의 언어가 등장하였다.
      5. 1980년대에는 객체지향 개념이 더욱 견고해지고 다양한 언어 표준이 이루어졌다.
      6. 1990년대에는 Java와 JavaScript, Python을 필두로 하여 프로그래밍 언어의 대중화가 시작되었다.
      7. 인터프리터는 고급언어 프로그램으로 작성된 문장을 하나씩 읽어서 수행한다. 컴파일러는 고급언어 프로그램을 기계어로 미리 번역한다. 하이브리드 구현은 고급언어 프로그램을 중간 코드 형태로 컴파일하고 이 중간 코드를 가상기계 상에서 해석한다.
      8. 프로그래밍 언어의 요구사항을 효과적으로 지원하기 위해 따라야 하는 프로그래밍 언어 설계 원칙으로는 규칙성, 추상화 지원, 복잡도 지원 등을 들 수 있다.9. 프로그래밍 언어의 평가 기준 중 대표적인 것으로 작성력, 가독성, 신뢰성, 직교성, 일관성, 확장성, 효율성, 유연성, 이식성 등을 들 수 있다.
      직교성: 언어 기능이 서로 간섭하지 않고 자유롭게 조합될 수 있는가, 더하기 기호는 더해지는 요소에 영향을 받지 않고 더하기라는 기능을 잘 하는가
      10. 프로그래밍 언어를 선택할 때는 언어 사용 커뮤니티가 활발하고 호의적인지, 언어의 특정 응용 분야가 있는지, 새로운 프로그래밍 패러다임을 지원하는지 등을 고려해야 한다.
  1. 프로그래밍 언어 페러다임
    1. 1. 프로그램을 작성하는 전형적인 방식을 프로그래밍 패러다임이라고 부른다.
      2. 명령형 프로그래밍 패러다임에서 프로그램은 특정 작업을 수행하기 위해 명령어가 나열된 것이다. 컴퓨터 하드웨어의 속성을 그대로 반영한 형태의 패러다임이다.
      3. 절차형 프로그래밍 패러다임은 문제를 해결하기 위한 절차를 서브루틴 단위의 절차로 구현하는 방식의 패러다임으로, 프로그램을 절차의 집합으로 간주한다.
      4. 함수형 프로그래밍 패러다임에서는 데이터를 값으로 간주하고, 주어진 데이터로부터 새로운 값을 생성하는 함수에 초점을 맞추어 프로그램을 작성한다
      .5. 논리 프로그래밍 패러다임에서는 문제의 조건을 논리식으로 표현하고 이 식을 바탕으로 어떤 사실을 입증해 나가는 방식으로 프로그램을 수행한다. 논리 프로그래밍 패러다임은 선언적 프로그래밍 패러다임의 일종이다.
      6. 객체지향 프로그래밍 패러다임은 데이터와 관련 연산을 합쳐 객체로 모형화하고, 객체 사이의 상호작용을 통해 프로그램을 수행하는 프로그래밍 패러다임이다.
      7. 프로그래밍 패러다임의 변화 배경으로는 응용 도메인의 변화, 프로그램 구성 방식의 변화, 계산 모델의 변화 등을 들 수 있다.
      8. 하나의 프로그래밍 언어가 한 패러다임만 지원하는 것은 아니다.
      9. 구조화 프로그래밍은 goto 논란으로부터 촉발되었는데 goto 없이 프로그램을 작성하는 패러다임이다.
      10. 다양한 프로그래밍 패러다임은 서로 배타적이라기보다 상호 보완적인 것으로 보는 것이 바람직하다.
4강 구문론과 의미론
1. 프로그래밍 언어는 문장을 정확하게 이해할 수 있도록 명확한 구문과 그 의미가 정의되어야 한다. 이를 프로그래밍 언어의 형식적 정의라 하며 이는 다시 구문론과 의미론으로 나눌 수 있다.2. 구문론은 프로그램의 표면적인 구조를 정의하는 것으로, 프로그램 작성 시 어떤 형태로 작성해야 하는지를 기술한다.3. 의미론은 프로그램의 내용적인 효과를 정의하는 것으로, 프로그램 실행 시 어떤 일이 일어나는지 그 의미를 기술한다.4. 프로그래밍 언어에서 구문은 문맥 자유 문법으로 표현된다. 문맥 자유 문법이란 문맥에 영향을 받지 않는 문법을 의미한다.5. 문맥 자유 문법을 표현하는 방법으로 BNF, EBNF, 구문 도표가 있다.6. 프로그래밍 언어에서 의미는 자연어로 표현되는 경우가 많지만, 엄밀한 표현을 위한 형식 의미론도 존재한다.7. 형식 의미론에서 다루는 표현 방법으로는 속성 문법, 기능적 의미론, 표기적 의미론, 공리적 의미론이 있다.
5강 구문 분석
1. 프로그램의 분석은 크게 어휘 분석과 구문 분석으로 나눌 수 있다.2. 어휘 분석을 통해 프로그램에서 사용된 단어인 토큰을 구별해 낸다. 토큰의 종류에는 연산자, 구분자, 식별자, 예약어 등이 있다.3. 식별자는 변수나 함수 등의 이름을 나타내는 토큰이다.4. 예약어는 프로그래밍 언어 자체에 정의되어 포함된 토큰으로 사용자 재정의가 불가능하다.5. 유도는 구문 규칙을 이용하여 주어진 프로그램을 만들어 내는 과정으로, 유도가 가능하다면 주어진 프로그램은 문법적 오류가 없다.6. 파스 트리는 유도를 트리 형태로 나타낸 것으로, 루트 노드는 시작 비단말 기호, 단말 노드는 단말 기호가 된다. 단말 노드를 왼쪽부터 오른쪽으로 차례로 나열하면 주어진 프로그램이 된다.7. 주어진 표현에 대한 파스트리가 존재하면 구문에 부합하는 표현이지만, 파스 트리가 존재하지 않으면 오류가 있는 표현이다.8. 모호한 문법은 동일한 표현에 대해 서로 다른 파스 트리가 만들어지는 문법으로, 하나의 프로그램이 서로 다른 결과를 도출할 수 있는 위험을 내포하고 있다.9. 모호한 문법은 문법을 명확하게 변경하여 모호성을 제거해야 한다.
6강 프로그래밍 언어의 구현
1. 프로그래밍 언어를 구현하기 위해서는 먼저 언어를 정의해야 하며, 이는 프로그램의 형태를 정의하는 구문론과 프로그램의 수행 의미를 정의하는 의미론으로 정의할 수 있다.2. 프로그래밍 언어 구현은 함수 모델로 해석할 수 있다.3. 전통적인 프로그래밍 언어는 기계의 단순한 명령어를 확대하는 형태로 구현한다. 그러나 새로운 패러다임의 프로그래밍 언어는 구현 모델을 추상기계로 만들고 이를 징검다리로 삼는 형태로 구현한다.4. 추상기계와 가상기계의 차이는 해당 기계의 구체적인 구현물이 있는지 여부이다.5. 컴파일러의 구현 단계는 크게 분석 단계와 생성 단계로 나눌 수 있다. 프로그래밍 언어에 의존적인 분석 단계를 전단부, 목적 기계에 의존적인 생성 단계를 후단부라고 부른다.6. 인터프리터를 구현할 때도 컴파일러의 전단부에 해당하는 분석 단계는 그대로 거친다. 하지만 전단부에서 생성된 중간 표현을 목적 코드로 바꾸는 대신 중간 표현을 순회하며 프로그램을 실행한다.7. 구문 트리와 중간 표현 외에 프로그래밍 언어 구현에 필요한 자료 구조로는 심볼 테이블과 환경을 들 수 있다.8. 언어 구현 시에는 프로그램이 실행되는 환경인 실행 환경도 고려해야 한다.9. 어휘 분석기는 어휘의 토큰과 속성을 분석하며, 구문 분석기는 토큰을 이용하여 구문 트리를 구성한다. 구문 트리는 파스 트리와 추상 구문 트리의 두 가지 형태가 있다.
7강 변수와 바인딩
1. 변수란 데이터를 저장하거나 나중에 사용할 수 있도록 메모리를 추상화한 것이다.2. 변수의 속성에는 변수명, 타입, 주소, 값이 있다. 변수의 값은 수행시간 동안 바뀔 수 있다.3. 바인딩이란 언어 구성 요소의 속성이 구체적으로 결정되는 것을 의미한다.4. 바인딩 시각이란 언어 구성 요소의 속성이 결정되는 시점을 의미한다. 바인딩 시각은 크게 정적 바인딩과 동적 바인딩으로 구분된다.5. 변수의 바인딩은 변수의 속성이 구체적으로 결정되는 것을 의미한다. 즉, 변수명 바인딩, 타입 바인딩, 주소 방인딩, 값 바인딩이 해당된다.6. 변수의 변수명 바인딩 방법과 타입 바인딩 방법에는 명시적 선언과 묵시적 선언이 있다.7. 변수의 정적 타입 바인딩은 컴파일 시점에 구문 분석을 통해 타입을 판단하고, 동적 타입 바인딩은 수행 시점에 대입할 값에 맞추어 타입을 판단하기에 계속 변할 수 있다.8. 변수의 수명은 변수가 메모리를 할당받고 있는 기간이다.9. 변수의 주소 바인딩 방법에는 자동 할당과 수동 할당이 있다.10. 변수의 정적 주소 바인딩은 로드 시점에 정적 세그먼트의 주소를 바인딩하고, 동적 주소 바인딩은 수행 시점에 동적 세그먼트의 주소를 바인딩한다.11. 정적 주소 바인딩을 하는 변수를 정적 변수, 동적 주소 바인딩을 하는 변수를 동적 변수라고 한다. 동적 변수는 스택 동적 변수와 힙 동적 변수로 나누어진다.
8장 변수의 영역
1. 변수의 영역이란 프로그램에서 변수를 사용할 수 있는 범위를 의미한다.2. 블록은 영역을 구분해 주는 단위로, 프로그램 문장들의 묶음이면서 그 안에서 변수 선언이 가능하다.3. 지역변수는 블록 안에서 선언된 변수이고, 비지역변수는 블록 밖에서 선언되었지만 블록 안에서 사용될 수 있는 변수이다.4. 참조 환경은 한 위치에서 사용할 수 있는 모든 변수의 모음으로, 해당위치의 모든 지역변수와 모든 비지역변수로 구성된다.5. 영역 규칙은 변수의 참조 위치를 결정하는 방법이다. 특히 현재 블록에서 선언되지 않은 자유변수에 대해 어디에서 선언된 비지역변수인지 혹은 오류인지 확인한다.6. 정적 영역 규칙은 블록들의 정적 내포 관계를 이용하여 변수의 참조 위치를 찾는 방법으로, 컴파일 시점에 결정할 수 있다. 동적 영역 규칙은 블록들의 동적 내포 관계를 이용하며, 수행 시점에 결정할 수 있다.7. 영역 구멍은 비지역변수가 같은 이름의 지역변수 때문에 보이지 않는 영역을 의미한다.8. 정적 영역 규칙은 동적 영역 규칙에 비해 안정적이고 수행 속도가 빨라서 대부분의 언어에서 사용한다.9. 전역변수는 어떤 블록에도 포함되지 않는 곳에서 선언된 변수로 영역은 프로그램 전체가 된다.10. 이름 공간은 관련성이 높은 변수와 함수를 하나의 묶음으로 관리하는 영역으로, 변수명처럼 영역 자체의 이름을 갖는다. C++는 이름 공간을 지원한다.
 
  1. 타입
    1. 1. 타입은 데이터 집합과 연산 집합의 결합이다. 데이터 집합은 처리 대상이 되는 데이터들의 집합이고, 연산 집합은 해당 데이터에 적용 가능한 연산의 집합이다.2. 프로그램 내 모든 연산 및 함수에 대해 적용 전후의 타입이 연산 및 함수의 정의와 일치한다면 그 프로그램은 타입 안전하다고 한다.3. 강타입 언어는 프로그램에 존재하는 모든 타입 오류를 검출해 내고, 약타입 언어는 일부 타입 오류를 허용한다. 무타입 언어는 타입 선언문이 없고 어떤 대상의 타입이 계속 바뀔 수 있다.4. 타입의 정의에 사용자가 개입할 수 있는지 여부에 따라 원시타입과 사용자정의타입으로 분류한다.5. 데이터 요소의 형태에 따라 단순타입과 복합타입으로 분류한다. 단순타입에는 정수형, 실수형, 문자형, 논리형, 열거형이 있다.6. 정수형은 정수 데이터를 다루는 타입으로, 데이터 집합에 포함되는 정수의 범위에 따라 다양한 타입이 존재한다. 연산 집합에는 사칙연산, 나머지 연산, 비트 연산, 관계 연산 등이 포함된다.7. 실수형은 실수 데이터를 다루는 타입으로, 데이터 집합에 포함되는 실수의 범위는 지수부와 가수부의 범위에 따라 달라진다. 연산 집합에는 사칙연산, 관계 연산 등이 포함된다.8. 문자형은 하나의 문자 데이터를 다루는 타입으로, 데이터 집합에 포함되는 문자의 범위는 ASCII 코드, 유니코드 등에 따라 달라진다. 연산 집합에는 관계 연산 등이 포함된다.9. 논리형은 참과 거짓의 두 논리 데이터를 다루는 타입으로, 연산 집합에는 논리 연산이 포함된다.10. 열거형은 순서 관계가 있는 이름들을 데이터로 다루는 타입으로 사용자정의타입이다. 데이터 집합에는 사용자가 지정한 이름들이, 연산 집합에는 관계 연산 등이 포함된다.
       
  1. 복합타입
    1. 1. 배열은 동질형 데이터의 모음으로 구성된 타입으로, 원소는 첨자로 구별한다. 차원은 배열에 사용되는 첨자의 개수이다.2. 배열은 첨자를 통해 원소의 주소를 쉽게 찾아야 한다. 2차원 이상의 배열은 저장 순서에 따라 행우선 저장 방법과 열우선 저장 방법이 있다.3. 문자열형은 문자열 데이터를 다루는 타입으로, 데이터 집합은 모든 문자열이 모인 집합이다. 연산 집합에는 언어에 따라 대입 연산, 연결 연산 등이 포함된다.4. 연관배열은 동질형 데이터의 순서 없는 모음으로 구성된 타입으로, 원소는 키로 구별한다. 데이터 집합은 모든 키 타입 데이터와 원소 타입 데이터의 쌍을 포함한다. 연산 집합에는 개별 원소에 대한 연산들이 포함된다.5. 구조체는 다양한 타입의 데이터의 모음으로 구성된 타입으로, 원소는 이름으로 구별한다. 데이터 집합은 원소의 개수와 각 원소의 타입에 따라 다양하게 존재한다. 연산 집합에는 초기화, 대입 연산 등이 포함된다.6. 공용체는 저장공간을 공유하는 데이터의 모음으로 구성된 타입으로, 한 원소의 값이 바뀌면 다른 원소들의 값도 영향을 받는다. 원소는 이름으로 구별하며, 데이터 집합은 각 원소의 타입에 따라 다양하게 존재한다. 연산 집합은 개별 원소 타입의 연산 집합을 따른다.7. 포인터형은 특정 데이터가 저장되는 주소 자체를 데이터로 다루는 타입으로, 특정 데이터의 타입은 사용자가 지정한다. 데이터 집합은 가용한 범위의 주소를 포함하며, 연산 집합에는 대입 연산, 덧셈, 뺄셈 연산 등이 포함된다.8. 참조형은 사용자가 지정하는 타입의 데이터가 저장된 주소 자체를 자신의 주소로 사용하는 타입이다. 데이터 집합과 연산 집합은 지정한 타입을 따른다.
  1. 수식
    1. 1. 수식이란 피연산자와 연산자로 구성되어 하나의 값을 나타내는 표현이다.2. 수식은 값을 나타내는 표현이며 문장은 처리를 나타내는 표현이다.3. 산술 연산자에는 사칙 연산자 외에도 언어에 따라 나머지 연산자, 부호 연산자 등이 포함된다.4. 피연산자의 개수에 따라 단항 연산자와 이항 연산자가 있고, 언어에 따라 삼항 연산자도 있다.5. 하나의 수식에 여러 연산자가 사용되는 경우 정해진 우선순위에 따라 연산을 수행한다. 같은 우선순위의 연산자들이 섞여 있는 경우에는 결합방향에 맞춰 연산을 수행한다.6. 결합방향에는 좌결합과 우결합이 있다. 같은 우선순위의 연산자들 중 좌결합은 가장 왼쪽 연산자부터, 우결합은 가장 오른쪽 연산자부터 연산을 수행하는 방법이다.7. 타입 변환은 주어진 타입의 값을 다른 타입의 값으로 변환하는 것으로, 묵시적 타입 변환과 명시적 타입 변환이 있다.8. 관계 연산자는 2개의 피연산자를 서로 비교하여 둘 사이의 관계가 관계 연산자와 일치하는지 여부를 확인한다. 관계 연산의 결과 값은 참 또는 거짓이다.9. 논리 연산자에는 논리곱 연산자, 논리합 연산자, 부정 연산자 등이 포함된다. 논리 연산의 피연산자와 결과 값은 참 또는 거짓이다.10. 논리 연산의 경우 단락 평가를 통해 모든 논리 연산을 수행하지 않고도 수식의 값을 얻을 수 있다.
  1. 문장
    1. 1. 문장이란 처리를 나타내는 표현으로, 선언문과 실행문으로 구분할 수 있다.2. 선언문은 변수나 서브프로그램을 이용할 수 있도록 준비를 해 준다.3. 실행문은 실제적으로 변수도 이용하고 서브프로그램도 이용하며 데이터를 처리한다. 실행문에는 변수의 값을 변경하는 대입문과 프로그램의 수행 흐름을 제어하는 제어문이 있다.4. C, C++, Java에서 대입문은 변수에 대입된 값을 나타내는 수식에 쌍반점을 찍어 만든 문장이다.5. C++는 조건 연산자를 이용하여 값이 대입될 변수를 선택할 수도 있다.6. C, C++, Java는 다양한 복합 대입 연산자를 지원한다. 또한 단항 대입 연산자도 있다.7. 대입문에서의 묵시적 타입 변환은 대입할 값의 타입을 변수의 타입으로 변환한다. 단, Java는 확대변환인 경우만 묵시적 타입 변환이 일어나고, 축소변환이 필요한 경우는 명시적 타입 변환을 이용해야만 오류가 발생하지 않는다.8. 조건문은 조건에 따라 서로 다른 처리를 하도록 제어하는 문장이다.9. 반복문은 원하는 문장을 반복해서 수행하도록 제어하는 문장이다.10. while문은 반복문장이 한 번도 수행되지 않을 수도 있지만, do-while문은 반복문장이 적어도 한 번은 수행하게 된다.
13. 서브프로그램 개념
1. 서브프로그램은 독자적인 입력과 출력을 갖춘 프로그램 조각으로 모듈화 프로그래밍을 지원하기 위해 기본적으로 필요한 기능이다.2. 서브프로그램으로 들어가는 입구는 일반적으로 하나인 반면 출구는 여러 곳이 될 수 있다.3. 서브프로그램은 반환값의 유무에 따라 프로시저와 함수로 분류할 수 있다. 프로그래밍 언어 개발 초기에는 반복적으로 사용되는 명령어 묶음을 서브루틴이라고 불렀다.4. 서브프로그램의 매개변수 개수, 순서, 타입을 매개변수 프로파일이라고 부르며 시그니처라고도 한다.5. 서브프로그램의 매개변수 프로파일과 함수 반환 타입을 합쳐 서브프로그램 프로토콜이라고 부른다. 정적 타입 언어의 경우 서브프로그램의 호출 전에 서브프로그램 프로토콜이 선언되어 있어야 한다.6. 외부로부터 전달될 정보를 받기 위해 서브프로그램 정의 부분에서 선언한 변수를 매개변수라 하고, 서브프로그램 호출 시 매개변수로 전달될 의도로 사용된 수식을 인수라고 한다. 매개변수를 형식인수(형식매개변수), 인수를 실인수(실매개변수)라고도 한다.7. 인수 전달의 의미적 모델로는 입력, 출력, 입출력 모드 세 가지가 있고, 개념적 모델로는 값 전달, 참조 전달이 있다. 구현 모델로는 값 전달, 결과 전달, 값-결과 전달, 참조 전달, 이름 전달이 있다.8. 입출력 모드 인수를 지원하기 위한 참조 전달은 별칭 문제를 발생시킬 수 있는데, 값-결과 전달을 이용하면 별칭 문제가 해결된다.9. 여러 용도로 가능할 수 있는 서브프로그램을 범용 서브프로그램이라고 하며 이는 다형 서브프로그램과 다목적 서브프로그램으로 구성된다.10. 모듈화 및 협업을 위해서는 분리 컴파일이나 독립 컴파일 기능이 필요하다.
  1. 서브프로그램 구현
    1. 1. 서브프로그램 호출과 복귀를 합쳐 서브프로그램 연결이라고 부르며 이때 제어 흐름뿐 아니라 자료 흐름도 관리해야 한다. 자료 흐름을 관리하기 위해 활성 레코드를 사용한다.2. 활성 레코드에는 서브프로그램의 데이터뿐 아니라 호출자의 상태, 복귀 주소, 반환값, 각종 관리 데이터가 저장된다.3. 초기 언어에서는 정적 활성 레코드 할당 방법을 사용했으나 이는 재귀호출이 불가능하다. 현재는 대부분 동적 활성 레코드를 사용한다.4. 활성 레코드에는 영역 규칙을 구현하기 위해 동적 링크와 정적 링크가 주로 사용된다.5. 정적 링크가 연결된 정적 체인은 정적 영역 규칙을 구현하기 위해 사용되고, 동적 링크가 연결된 동적 체인은 동적 영역 규칙을 구현하기 위해 사용된다.6. 정적 체인을 거슬러 올라가는 부담을 줄이기 위해서 디스플레이를 활용할 수 있다.7. 동적 영역 규칙에서 모든 변수에 대한 정보를 한곳에서 관리하며 변수를 참조하는 방법을 얕은 참조라고 한다. 얕은 참조에는 변수 스택 방법과 중앙 테이블 방법이 있다.8. 과거 민감 서브프로그램이란 이전의 호출 내용을 기억하는 서브프로그램이다.9. 코루틴이란 여러 개의 진입 지점을 스스로 관리하는 서브프로그램을 뜻한다. 코루틴은 ‘호출된다’고 하지 않고 ‘재개된다’고 한다.
  1. 객체지향과 다형성
    1. 1. 추상화란 복잡한 대상을 간략하게 나타내는 것을 뜻하는데, 이는 프로그래밍에 필수적인 작업이다.2. 프로그래밍 언어에서 제공하는 추상화 종류는 크게 제어 추상화와 자료 추상화로 나눌 수 있다.3. 여러 요소를 하나의 단위로 묶을 수 있는 기능을 캡슐화라 하고, 구현 세부 사항을 외부에 숨기고 인터페이스만 외부에 공개하는 기능을 정보 은닉이라고 부른다.4. 자료 집합과 적용 가능한 연산을 함께 선언한 타입을 추상 자료형이라고 한다.5. 객체란 특정 상태를 유지하며 외부 요구에 반응하는 행태를 보이는 대상을 추상화시킨 것이다.6. 객체에 따라 호출 메소드가 결정되도록 하기 위해서는 호출 메소드의 늦은 바인딩이 필요한데, 가상함수 테이블(VTab)로 늦은 바인딩을 구현한다.7. 여러 타입의 데이터를 같은 이름으로 처리할 수 있는 특성을 다형성이라고 한다.8. 다중 상속을 지원하면 다이아몬드 상속 문제가 발생한다.9. 객체를 직접 생성할 수 없을 정도로 극도로 추상화된 클래스를 추상 클래스라고 한다.10. 추상 클래스의 개념을 확장한 것으로 인터페이스와 트레잇을 들 수 있다.
Share article

veganee

RSS·Powered by Inblog