오랜 고민끝에 (1주일 가량?^^) 오실로스코프를 영입하기로 결심했고 주문한지 40일이나 지나서 배송받았다. ㅠㅠ

먼저 제목과 같이 Hantek DSO5202P를 골랐는데 이유는 간단하다.

 

  1. 내가 IoT를 개발하면서 회로에 대해서 깊게 다루지 않을 것이 분명해 보인다.
    - 다른 말로 단순 동작만 볼 것이라는 것. 무슨 RF신호나 무선 신호같은 수준높은 일은 아니라는 확신.
  2. 그렇다면 고민했던 Tektronix같은 유명 메이커까지 필요하지 않다. (사실 메이커 잘 모르는 수준임.ㅎㅎ)
    - 메이커는 메이커 값을 하겠지만 비싸다. 세상에 싸면서 좋은건 없다는 나의 지론도 있다.
  3. 결론은 오실로스코프가 없으니 보드 동작에 대해 전혀 알 수가 없으니 있긴 있어야 되는데... 그렇다고 내가 전문적으로 필요하지 않으니 싸면서 적당한것을 고르다 보니 Hantek을 골랐고 100MHz 대역과 200MHz의 차이가 5만원 가량이어서 조금 더 투자하기로 하고 DSO5202P를 선택하게 되었다.

어쨌든 개발하는데 잘 쓰고 있고 진작 살껄 후회도 조금 하는 중이다.

개봉 전
나름 꼼꼼한 포장
설렌다 ㅎ
아우~ 좋아~
부팅 화면 1
부팅 화면 2
테스트 신호는 5V 1KHZ
버튼부

나는 많은 기능을 다 쓰지 않겠지만 오실로스코프에 대해 검색했을때 다른 블로거분은 "Single SEQ"가 버튼으로 있어 마음에 든다고 했던 글을 본 기억이 있다.

x축 시간 조절, y축 전압조절, trigger 조절, auto set정도가 주요 사용 기능이므로 다른 기능들은 차차 필요에 의해 알아가 보도록 할 예정이다.

 

그리고 추가로 프로브도 대역폭이 있었다.... 원래 가지고 있었던 60MHz프로브로도 테스트 신호를 잡았는데 별 차이를 못느겼다. 사실 앞서 말했지만 무선신호를 잡아야하는 그런 전문적인 상황에서 대역폭이 중요하다고 알고 있고, 나 같이 on/off같은 신호(예를 들어, digitalWrite(relayPin_done, HIGH);)에서는 대역폭이 중요하지는 않아보인다. (사실 wifi가 2.4GHz, 5GHz라는 정도만 알지... 그게 뭘 의미하는지... 깊게는 모른다.^^;)

 

마지막으로 내가 알아봤던 가격은 tektronix TBS2102가 ebay에서 110만원 가량이었고, hantek DSO5202P는 알리에서 30초반으로 구입했다.

'IoT' 카테고리의 다른 글

Intel Edison and Arduino Breakout Kit  (0) 2015.02.17
DocFlavor flavor = DocFlavor.INPUT_STREAM.PDF;
FileInputStream fis = null;
try {
	fis = new FileInputStream("sample.pdf");
} catch (FileNotFoundException e) {
	e.printStackTrace();
}
	Doc doc = new SimpleDoc(fis, flavor, null);
	pdfService.createPdfLabel();
try {
	docPrintJob.print(doc, printRequestAttributeSet);
} catch (PrintException e) {
	e.printStackTrace();
}

생산 현장 프로젝트 중에 제품 생산시 바코드를 프린터로 출력해야하는 시나리오를 구현하기 위해 javax.print의 API를 개발했는데 아래와 같은 에러가 발생 하였다.

javax.print.PrintException: already printing
	at java.desktop/sun.print.UnixPrintJob.print(UnixPrintJob.java:317)
	at com.dhptec.waco.service.impl.PrintServiceImpl.printLabel(PrintServiceImpl.java:122)
	at com.dhptec.waco.controller.PrintController.print(PrintController.java:34)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:197)
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:141)
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:894)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)
	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1061)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:961)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
	at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:652)
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:733)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:93)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)

정확하게는 처음 시작하고 한 번은 잘 동작하고 두 번째부터 위와 같은 에러가 발생한다. 그런데 구글링을 해도 딱히 정확한게 없어서 API부터 다시 봤다.

javax.print.DocPrintJob public abstract void print(javax.print.Doc doc,
                           javax.print.attribute.PrintRequestAttributeSet attributes)
throws javax.print.PrintException
Prints a document with the specified job attributes. This method should only be called once for a given print job. Calling it again will not result in a new job being spooled to the printer. The service implementation will define policy for service interruption and recovery. When the print method returns, printing may not yet have completed as printing may happen asynchronously, perhaps in a different thread. Application clients which want to monitor the success or failure should register a PrintJobListener.
Print service implementors should close any print data streams (ie Reader or InputStream implementations) that they obtain from the client doc. Robust clients may still wish to verify this. An exception is always generated if a DocFlavor cannot be printed.

Params:
doc – the document to be printed. It must be a flavor supported by this PrintJob.
attributes – the job attributes to be applied to this print job. If this parameter is null then the default attributes are used.
Throws:
javax.print.PrintException – the exception additionally may implement an interface that more precisely describes the cause of the exception
FlavorException. If the document has a flavor not supported by this print job.
AttributeException. If one or more of the attributes are not valid for this print job.

내용인 즉, 이 메서드는 주어진 인쇄작업에 대해 한 번만 호출해야합니다. 다시 호출해도 새 작업이 프린터로 스풀링되지 않습니다. 그렇다면 DocPrintJob을 프린트 할 때마다 새로 생성해야된다는 뜻으로 풀이되어 아래 코드로 변경했다.

@Configuration
public class PrintConfig {

    @Autowired
    private LabelPrintJobAdapter labelPrintJobAdapter;

    @Bean
    public PrintService defaultPrintService(){
        return PrintServiceLookup.lookupDefaultPrintService();
    }

    @Bean
    @RequestScope // 추가한 내용
    public DocPrintJob docPrintJob() {
        PrintService defaultPrintService = defaultPrintService();
        DocPrintJob printJob = defaultPrintService.createPrintJob();
        printJob.addPrintJobListener(labelPrintJobAdapter);
        return printJob;
    }
}

PrintConfig.java에서 DocPrintJob을 singleton으로 주입받았는데 request scope으로 바꾸니 문제가 해결되었다.

역시 구글링이 대부분의 문제들은 해결되지만 안되면 처음부터 차근차근 해법을 찾아가는 것도 중요하다.

npx로 typescript 프로젝트를 만들었을때 vscode에서 위와 같은 에러가 발생했다.

구글링 중에 tsconfig.json의 내용을 바꾸라는 내용이 다수였는데 이 방법 보다 더 정확해 보이는 해결책을 찾았다.

stackoverflow.com/questions/50432556/cannot-use-jsx-unless-the-jsx-flag-is-provided

 

Cannot use JSX unless the '--jsx' flag is provided

I have looked around a bit for a solution to this problem. All of them suggest adding "jsx": "react" to your tsconfig.json file. Which I have done. Another one was to add "include: []", which I hav...

stackoverflow.com

cmd + shift + p -> select typescript version -> Use Workspace Version 4.x.x 로 변경하니 error가 사라졌다.

이걸 설정하기 전 typescript버전은 3.x.x였는데 4.x.x로 변경했더니 문제가 사라졌다.

'Programming > JavaScript' 카테고리의 다른 글

event.stopPropagation(), event.preventDefault () 이해하기  (0) 2014.10.20
[JAVASCRIPT] replace  (0) 2013.05.08

VPC보다 VPN(Virtual Private Network) 먼저

회사 내부의 네트워크

VPN은 한국어로 “가상사설망"이라합니다. 앞에 “가상"이라는 단어에서 알 수 있듯 실제 사설망이 아닌 가상의 사설망입니다. 만약 위 그림과같이 회사의 네트워크가 구성되어있고 보안상의 이유로 직원간 네트워크를 분리하고싶다면 기존 인터넷선 선공사도 다시해야하고 건물의 내부선을 다 뜯어고쳐야하며 다시 전용선을 깔아주어야합니다. 이를위해 가상의 망 VPN을 사용하게됩니다.

VPN을 구축한 네트워크

VPN은 네트워크A와 네트워크B가 실제로 같은 네트워크상에 있지만 논리적으로 다른네트워크인것처럼 동작합니다. 이를 우리는 ‘가상사설망'이라고합니다.

VPC(Virtual Private Cloud)

VPC가 없는구조

VPC가 없다면 EC2 인스턴스들이 서로 거미줄처럼 연결되고 인터넷과 연결됩니다. 이런 구조는 시스템의 복잡도를 엄청나게 끌어올릴뿐만 아니라 하나의 인스턴스만 추가되도 모든 인스턴스를 수정해야하는 불편함이 생깁니다. 마치 인터넷 전용선을 다시까는것과 같습니다.

VPC가를 적용한구조

VPC를 적용하면 위 그림과같이 VPC별로 네트워크를 구성할 수 있고 각각의 VPC에따라 다르게 네트워크 설정을 줄 수 있습니다. 또한 각각의 VPC는 완전히 독립된 네트워크처럼 작동하게됩니다.

VPC를 구축하는 과정

VPC를 구축하기위해서는 VPC의 아이피범위를 RFC1918이라는 사설아이피대역에 맞추어 구축해야합니다. 사설아이피란 무엇일까요? 인터넷을 위해 사용하는것이 아닌 우리끼리 사용하는 아이피주소 대역입니다. 예를들어보겠습니다. 누군가 “안방에서 리모컨좀 가져다달라”하면 저는 옆집을 가는게 아닌 우리집에 있는 “안방”으로 찾아갑니다. 안방이 프라이빗아이피(사설아이피) 우리집 주소가 퍼블릭아이피입니다.

옆집도 안방이 있고 우리집도 안방이 있지만 서로 안방을 들었을때 헷갈리지 않습니다. “안방”, “작은방”, “큰방”처럼 내부에서 쓰는 주소를 사설아이피 대역이라고 부르며 내부 네트워크내에서 위치를 찾아갈때 사용합니다. 물론 내 친구나 혹은 동생의 친구가 찾아올때는 도로명주소(퍼블릭아이피)를 알려주면되고 같은집(우리집)에사는(동일한 네트워크 상 존재하는) 내가 동생하테갈때는 동생방(사설아이피)로 찾아갑니다.

VPC에서 사용하는 사설 아이피 대역은 아래와같습니다.

- 10.0.0.0 ~ 10.255.255.255(10/8 prefix)

- 172.16.0.0 ~ 172.31.255.255(182.16/12 prefix)

- 192.168.0.0 ~ 192.168.255.255(192.168/16 prefix)

한번 설정된 아이피대역은 수정할 수 없으며 각 VPC는 하나의 리전에 종속됩니다. 각각의 VPC는 완전히 독립적이기때문에 만약 VPC간 통신을 원한다면 VPC 피어링 서비스를 고려해볼 수 있습니다.

서브넷

VPC를 만들었다면 이제 서브넷을 만들 수 있습니다. 서브넷은 VPC를 잘개 쪼개는 과정입니다. 서브넷은 VPC안에 있는 VPC보다 더 작은단위이기때문에 연히 서브넷마스크가 더 높게되고 아이피범위가 더 작은값을 갖게됩니다. 서브넷을 나누는 이유는 더 많은 네트워크망을 만들기 위해서입니다.

각각의 서브넷은 가용영역안에 존재하며 서브넷안에 RDS, EC2와같은 리소스들을 위치시킬 수 있습니다.

라우팅 테이블과 라우터

네트워크 요청이 발생하면 데이터는 우선 라우터로 향하게됩니다. 라우터란 목적지이고 라우팅테이블은 각 목적지에 대한 이정표입니다 데이터는 라우터로 향하게되며 네트워크 요청은 각각 정의된 라우팅테이블에따라 작동합니다. 서브넷A의 라우팅테이블은 172.31.0.0/16 즉 VPC안의 네트워크 범위를 갖는 네트워크 요청은 로컬에서 찾도록 되어있습니다. 하지만 그 이외 외부로 통하는 트래픽을 처리할 수 없습니다.이때 인터넷 게이트웨이를 사용합니다.

인터넷게이트웨이

인터넷게이트웨이는 VPC와 인터넷을 연결해주는 하나의 관문입니다. 서브넷B의 라우팅테이블을 잘보면 0.0.0.0/0으로 정의되어있습니다. 이뜻은 모든 트래픽에 대하여 IGA(인터넷 게이트웨이) A로 향하라는뜻입니다. 라우팅테이블은 가장 먼저 목적지의 주소가 172.31.0.0/16에 매칭되는지를 확인한 후 매칭되지 않는다면 IGA A로 보냅니다.

인터넷과 연결되어있는 서브넷을 퍼블릭서브넷, 인터넷과연결되어있지않는 서브넷을 프라이빗서브넷이라고합니다.

네트워크 ACL과 보안그룹

네트워크 ACL과 보안그룹은 방화벽과 같은 역활을 하며 인바운드 트래픽과 아웃바운드 트래픽 보안정책을 설정할 수 있습니다. 먼저 보안그룹은 Stateful한 방식으로 동작하는 보안그룹은 모든 허용을 차단하도록 기본설정 되어있으며 필요한 설정은 허용해주어야합니다. 또한 네트워크ACL과 다르게 각각의 보안그룹별로도 별도의 트래픽을 설정할 수 있으며 서브넷에도 설정할 수 있지만 각각의 EC2인스턴스에도 적용할 수 있습니다.

네트워크 ACL은 Stateless하게 작동하며 모든 트래픽을 기본설정되어있기때문에 불필요한 트래픽을 막도록 적용해야합니다. 서브넷단위로 적용되며 리소스별로는 설정할 수 없습니다. 네트워크ACL과 보안그룹이 충돌한다면 보안그룹이 더 높은 우선순위를 갖습니다.

NAT 게이트웨이

NAT 게이트웨이는 프라이빗서브넷이 인터넷과 통신하기위한 아웃바운드 인스턴스입니다. 프라이빗 네트워크가 외부에서 요청되는 인바운드는 필요없더라도 인스턴스의 펌웨어나 혹은 주기적인 업데이트가 필요하여 아웃바운드 트래픽만 허용되야할 경우가 있습니다. 이때 퍼블릭 서브넷상에서 동작하는 NAT 게이트웨이는 프라이빗서브넷에서 외부로 요청하는 아웃바운드 트래픽을 받아 인터넷게이트웨이와 연결합니다.

마치며

VPC의 목적은 다양할 수 있지만 일반적으로 보안을위해 AWS 리소스간 허용을 최소화하고 그룹별로 손쉽게 네트워크를 구성하기위해 많이사용합니다.이외에도 독립적인 VPC간 네트워크 통신을 위한 VPC피어링, 기존 사용하는 온프레미스와 VPC를 연결하는 AWS Diarect Connect, VPC에서 발생하는 로그를 기록하는 VPC FLow Logs와같은 서비스가있습니다.

 

- 출처 : medium.com/harrythegreat/aws-%EA%B0%80%EC%9E%A5%EC%89%BD%EA%B2%8C-vpc-%EA%B0%9C%EB%85%90%EC%9E%A1%EA%B8%B0-71eef95a7098

 

[AWS] 가장쉽게 VPC 개념잡기

가장쉽게 VPC 알아보기

medium.com

Harry The Great

#9 11.82 npm ERR! code ENOENT
#9 11.83 npm ERR! path git
#9 11.83 npm ERR! errno -2
#9 11.83 npm ERR! enoent Error while executing:
#9 11.83 npm ERR! enoent undefined ls-remote -h -t ssh://git@github.com/eligrey/FileSaver.js.git
#9 11.83 npm ERR! enoent
#9 11.83 npm ERR! enoent
#9 11.83 npm ERR! enoent This is related to npm not being able to find a file.
#9 11.85
#9 11.85 npm ERR! A complete log of this run can be found in:
#9 11.85 npm ERR!     /root/.npm/_logs/2020-11-10T14_49_13_350Z-debug.log

이거로 한참을 헤매었다.... 아오~

 

FROM node:14.15-alpine
WORKDIR /app
COPY ["package.json", "package-lock.json*", "npm-shrinkwrap.json*", "./"]
RUN npm install
COPY . .
EXPOSE 3000
CMD ["npm", "start"]

dockerfile이다... 별 문제 없어 보인다. 그러니 저런 에러가 나오면 멘붕이지...

alpine 이미지의 특성인지는 모르겠지만 "git@github.com/eligrey/FileSaver.js.git" 이 repository를 땡겨오는데 문제가 생겼고 path git 이라는 문구도 보인다... 설마설마... alpine에 git이 없나??? (npm install인데 git에서도 땡겨오는지는 몰랐음....)

 

RUN git --verion을 추가하기에 이르렀다. 예상대로 git 명령어 없음.

 

RUN npm install 전에 아래 추가하여 git 설치 했더니 문제 없이 docker image가 build되었다.

 

RUN apk update && apk upgrade && apk add --no-cache bash git openssh

docker build 후에 docker-compose 설정해서 실행하는데 "sh: react-scripts: not found"를 못찾는 상황이 생겼다.

VS code의 docker plug-in을 통해 Dockerfile을 생성했는데 이 부분에서 문제 였다.

 

RUN npm install -g react-scripts

 

위처럼 docker container상에는 react-scripts가 설치 되어 있지 않아서 발생한 문제다.


docker-compose 문제가 아니라 dockerfile 문제로 자동 생성한 것은 역시나 꼼꼼히 다시 봐야 겠다는 생각이 들었다.

'Operating System > Docker | Kubernetes' 카테고리의 다른 글

npm ERR! code ENOENT  (0) 2020.11.11
docker-compose mysql Connection refused  (2) 2020.09.18

먼저 test용 docker를 docker-compose를 사용해서 간단히 구축했다.

 

그런데... DB connection이 안된다...

 

Caused by: java.net.ConnectException: Connection refused (Connection refused)

 

흠... 구글링 잘 알되고 (키워드가 뭔가 없었던 것 같다..) application.yml과 docker-compose.yml을 다시 훑어 봐도 문제는 없어 보였다.

 

예전 기억을 떠올리고 떠올리다가 번개처럼 스친 기억!

---
spring:
  profiles: dev
# ===============================
# = DATA SOURCE
# ===============================
  datasource:
    hikari:
      driver-class-name: com.mysql.cj.jdbc.Driver
      jdbc-url: jdbc:mysql://localhost:3306/vermont
      ....

평소 같았으면 전혀 문제 없는 내용....

version: '3'

services:
  db:
    image: mysql:5.7
    restart: always
    command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    environment:
      MYSQL_ROOT_PASSWORD: XXXXX
      MYSQL_USER: XXXXX
      MYSQL_PASSWORD: XXXXX
      MYSQL_DATABASE: vermont
    volumes:
      - db-data:/var/lib/mysql
    ports:
      - 3306:3306
    expose:
      - 3306
  adminer:
    image: adminer
    restart: always
    ports:
      - 8080:8080
  vermont:
    image: vermont
    restart: always
    ports:
      - 8888:8888
    depends_on:
      - db
volumes:
  db-data:

그러나 docker-compose로 구성하면 다른 얘기가 된다.

위와 같이 services 아래 서비스 이름을 지정하게 되는데 connection url도 서비스 이름으로 접근해야 한다.

그래서 jdbc:mysql://localhost/vermont...가 아닌 jdbc:mysql://db/vermont....로 바꿔야 한다.


알고 있던 내용이었는데... 역시 노트 해놓지 않으니 1시간 허비... 구글링도 잘 못찾았던 것 같다. 노트노트노트!

'Operating System > Docker | Kubernetes' 카테고리의 다른 글

npm ERR! code ENOENT  (0) 2020.11.11
docker-compose react sh: react-scripts: not found  (0) 2020.09.19

요즘 프로젝트 setup부터 잔업무까지 몸이 10개라도 모자른다.

그런데 티비에 나오는 유명한 사람들은 왜이리 똑똑하고 일도 잘하는것 같지?

얼마전 유퀴즈에 나온 PUBG 김창한대표, 하트시그널에 나온 천인우씨, sns에 알려진 개발자 셀럽(?)분들을 보면 다들 천재같다.

이럴때마다 드는 생각....

 

나도 천재이고 싶다. ㅜㅠ

'Doodle' 카테고리의 다른 글

브레빌 870  (1) 2020.07.10
탄천은 사랑입니다.  (0) 2020.06.12
10 Communication Patterns Used by Great Leaders  (0) 2020.05.08
내가 그의 이름을 불러주었을 때  (0) 2020.04.22

https://martinfowler.com/articles/microservice-testing/

 

Testing Strategies in a Microservice Architecture

The microservice architectural style presents challenges for organizing effective testing, this deck outlines the kinds of tests you need and how to mix them.

martinfowler.com

MSA에서 test전략

가정용 에스프레소 머신
완전 신세계다.
드립과는 다른 매력이 있어서 이제 커피는 집에서만 먹을 듯 하다 ^^

'Doodle' 카테고리의 다른 글

천재이고 싶다...  (0) 2020.08.21
탄천은 사랑입니다.  (0) 2020.06.12
10 Communication Patterns Used by Great Leaders  (0) 2020.05.08
내가 그의 이름을 불러주었을 때  (0) 2020.04.22

+ Recent posts