2026년 7월 1일 수요일

$10 monthly Gen AI & Cloud credits 사용하기

구글 ai pro 구독하면 cloude에서 사용가능한 10달러 크레딧을 매달 준다고 한다.

aistudio나 antigravity, 구글 클라우드 등등에서 사용가능한듯 하다.


아래의 개발자 프로그램 페이지에 가서 혜택을 선택하고 적용할 결제 계정을 선택한다.

 https://me.developers.google.com/benefits


크레딧이 매월 한번씩 준다고 들었는데 왜 2개 있는지 모르겠다.

첫번째꺼는 1회성으로 한번 준거 같다.

결제 계정을 선택 후 apply 누르면 적용된다.

추가된 크레딧은 구글 클라우드 콘솔 > 결제 >크레딧에서 확인할 수 있다.


사용량은 실시간으로 반영 되지만 크레딧에서 빠져나가는건 조금 시간차가 있는듯 하다.


충전한 선불 크레딧이 있었지만 프로모션 크레딧이 먼저 사용되고 있다.
 aistudio에서 지출내역을 보니 처음에는 왜 비용이 누적되고 있는데 그래프가 없나 했는데, 생각해보니 절감항목이 있다. 쿠폰으로 처리되고 있어서 0으로 표시되는듯 하다.

2025년 3월 17일 월요일

android a tag 안의 이미지 클릭 오류

 웹뷰에서 a tag 안의 이미지를 클릭시 링크 주소로 이동하는게 아니라 이미지 주소가 전달되는 이슈가 생겼음.

 예)<a href='linkA' target='_blank'><img src='srcB'/></a> 

linkA가 아니라 srcB가 열림

onCreateWindow에서 타입을 체크해서 

타입이 'WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE ' 라면

아래와 같이 href의 url 을 가져와서 처리

@Override
public boolean onCreateWindow(WebView view, final boolean isDialog, boolean userGesture, android.os.Message resultMsg) {
if (!isDialog) {
WebView.HitTestResult result = view.getHitTestResult();
String data = result.getExtra();
if(result.getType()== WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE) {
Message href = view.getHandler().obtainMessage();
view.requestFocusNodeHref(href);
String url2 = href.getData().getString("url");
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url2));
mActivity.startActivity(intent);
return false;

}
}

2025년 3월 13일 목요일

삼성 원격단말 테스트

삼성 개발자 사이트에 접속: https://developer.samsung.com/remote-test-lab




다음과 같은 화면이 보이게 된다.


난 갤럭시S로 테스트 해보고 싶다.

available을 누르면 다음과 같이 단말 선택 상세정보가 뜬다.


단말 위치가 글로벌 하게 있다. 사용시간 30분당 2 credit이 소모된다.
credit은 하루에 로그인 하면 20credit 준다고 되어 있고 우측 상단에 내 크래딧을 누르면 하루에 10코인을 충전해 준다.
FAQ 참조

start를 누르면 원격 단말이 실행된다.
원격 디버깅을 시작해 보자

connect를 누르면 RDB를 설치하라고 나온다.



다운로드를 누르면 rdb.zip파일이 다운로드 되는데 이를 압축 풀어서 실행하면 된다. 다운받아서 rdb.exe를 실행하면 다음과 같은 화면이 뜬다.

여기서 adb가 포함된 오류가 발생하면 환경변수에 adb경로가 추가되어 있지 않아서 그렇다. 시스템 변수에 추가해 주자. 
이제 android studio에 접속해 보면 디바이스 관리 탭에 원격 디바이스가 보인다.

이제 남은 시간동안 열심히 테스트 해보면 된다!!







구글 트랜드 rss 파싱하기

 

1️⃣ 패키지 설치


npm install axios fast-xml-parser

#rss-parser도 사용해 봤지만 rss-parser는 네임스페이스를 파싱하지 못한다고 한다.

2️⃣ Google Trends RSS 파싱 코드 (google-trends-parser.js)


const axios = require("axios"); const { XMLParser } = require("fast-xml-parser"); const GOOGLE_TRENDS_RSS_URL = "https://trends.google.com/trending/rss?geo=US"; async function fetchGoogleTrends() { try { // RSS 피드 가져오기 const response = await axios.get(GOOGLE_TRENDS_RSS_URL); // XML 파싱 const parser = new XMLParser({ ignoreAttributes: false, parseTagValue: true }); const feed = parser.parse(response.data); // RSS 구조 확인 const items = feed.rss.channel.item; if (!items) { console.error("❌ No items found in the RSS feed."); return; } // 트렌드 뉴스 출력 items.forEach((item, index) => { console.log(`📌 Trend ${index + 1}: ${item.title}`); console.log(` 📰 Link: ${item.link}`); console.log(` 🖼️ Image: ${item["ht:picture"]}`); console.log(` 📰 Source: ${item["ht:picture_source"]}`); // ht:news_item 처리 if (item["ht:news_item"]) { const newsItems = Array.isArray(item["ht:news_item"]) ? item["ht:news_item"] : [item["ht:news_item"]]; console.log(` 🗞️ News Articles:`); newsItems.forEach((news, idx) => { console.log(` ${idx + 1}. ${news["ht:news_item_title"]}`); console.log(` 🔗 ${news["ht:news_item_url"]}`); console.log(` 🖼️ ${news["ht:news_item_picture"]}`); console.log(` 📰 Source: ${news["ht:news_item_source"]}\n`); }); } console.log("------------------------------------------------------"); }); } catch (error) { console.error("❌ Error fetching Google Trends:", error.message); } } fetchGoogleTrends();

2025년 2월 24일 월요일

유튜브 url에서 id 추출

youtube의 여러 url 주소형식에서  id만 추출하여 embed url로 생성


function getYoutubeUrl(url){
// YouTube URL을 처리하기 위한 정규 표현식
const regex = /^(?:https?:\/\/)?(?:www\.|m\.)?(?:youtube\.com|youtu\.be)\/(?:.*v(?:\/|=)|(?:.*\/)?)([^#&?]*).*/;

const match = url.match(regex);

// 정규 표현식에 일치하는 부분이 있으면 동영상 ID 추출, 아니면 입력값 그대로 반환
return match ? 'https://youtube.com/embed/'+match[1] : url;
}


2025년 2월 19일 수요일

윈도우에서 여러 파일명 바꾸기

PowerShell을 사용하여 파일 이름 패턴 변경하기

1. Get-ChildItem cmdlet으로 파일 목록 가져오기

먼저 Get-ChildItem cmdlet을 사용하여 파일 목록을 가져옵니다.

PowerShell에서 실행
```
Get-ChildItem -Path ".\your_directory_path" -Filter "noto-sans-kr-*"
```
  • -Path: 파일이 있는 디렉토리 경로를 지정합니다.
  • -Filter: 파일 이름 패턴을 지정합니다. 여기서는 noto-sans-kr-* 패턴을 사용하여 "noto-sans-kr-"로 시작하는 모든 파일을 선택합니다.

2. Rename-Item cmdlet으로 파일 이름 변경하기

다음으로 Rename-Item cmdlet을 사용하여 파일 이름을 변경합니다.

PowerShell에서 실행
``` #실행명령
Get-ChildItem -Path ".\your_directory_path" -Filter "noto-sans-kr-*" | Rename-Item -NewName { $_.Name -replace "noto-sans-kr", "notoSansKr" }
```
  • Rename-Item: 파일 이름을 변경하는 cmdlet입니다.
  • -NewName: 새로운 파일 이름을 지정합니다. 여기서는 스크립트 블록 {} 안에서 $_ 변수를 사용하여 현재 파일 객체를 참조하고, -replace 연산자를 사용하여 "noto-sans-kr"을 "notoSansKr"로 변경합니다.

주의 사항

  • 위 코드를 실행하기 전에 반드시 백업을 해두세요. 파일 이름 변경은 되돌릴 수 없으므로 주의해야 합니다.
  • -replace 연산자는 대/소문자를 구분하지 않습니다. 만약 대/소문자를 구분하여 변경하고 싶다면 -creplace 연산자를 사용하세요.
  • 위 코드에서 your_directory_path는 실제 디렉토리 경로로 변경해야 합니다.
변경전

변경후


2024년 12월 26일 목요일

타입스크립트 기존 컴포넌트에 다른 타입 추가 하기

1. 유니온 타입

interface Props {
article : Article|CompactArticle;
}

 사용후 타입가드 

export const isArticleNotCompact = (props:CompactArticle|Article): props is Article => {
return 'pubdate' in props && 'author' in props ;
}
{
isArticleNotCompact(article) &&//Caompact에는 없는 속성들 처리
<>
<div className="entry-meta font-medium position-relative d-flex mt-md-4 d-none d-md-block d-lg-block">
<span> {TimeAgo(article.pubdate as string)}</span>
<span className={article.author && "vertical-divider ml-5 mr-5"}></span><span >{article.author}</span>
</div>
<div className="entry-meta font-medium position-relative d-flex mt-md-4 d-block d-md-none d-lg-none">
<span> {TimeAgo(article.pubdate as string)}</span>
</div>
</>
}

2. extends 하기

export interface CompactArticle {
id: number
title?: string | undefined
badge? : string | undefined
sub_title?: string | undefined
summary?: string | undefined
image?: string | undefined
url: string
related?: []|Related[] | undefined
}
export interface Article extends CompactArticle{
author? : string | undefined
summary? : string | undefined
description? : string | undefined
// 필요한 타입 추가 및 재정의

}

타입을 extends 하면 기존의 컴포넌트를 바꾸지 않고도 사용 가능

2024년 12월 24일 화요일

Cannot find module 'next/dist/server/future/route-modules/pages/vendored/contexts/amp-context'

 nextjs를 output='standalone'으로 빌드시 

Cannot find module 'next/dist/server/future/route-modules/pages/vendored/contexts/amp-context'

오류가 발생


원인 

build 하고 standalone/.next/node_modules/next/dist 폴더에

shared 디렉토리만 존재하고 있음. 모듈 빌드가 제대로 되지 않은듯


해결책

nextjs 버전을 변경한다. 

^14.2.21 버전에서 ^14.2.13으로 변경

2024년 5월 20일 월요일

services. Additional property annotations is not allowed

docker 컨테이너 로그 수집하기 위해 프로메테우스와 익스포터 설치중 에러

아래와 같이 컴포즈 파일 생성
  node-exporter:
    image: prom/node-exporter:latest
    container_name: node-exporter
    restart: unless-stopped
    labels:
      service.discovery.prometheus: "true"
   annotations:
    service.annotations.prometheus.io/scrape: "true"
    volumes:
      - /proc:/host/proc:ro
      - /sys:/host/sys:ro
      - /:/rootfs:ro
    command:
      - '--path.procfs=/host/proc'
      - '--path.rootfs=/rootfs'
      - '--path.sysfs=/host/sys'
      - '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)'
    expose:
      - '9100'
    networks:
      monitoring:
        aliases:
          - exporter
    deploy:
      mode: global
---------------------------------
컴포즈 버전 3.8 이전 이후 설정이 다르다.


For Docker Compose versions above 3.8:
YAML
node-exporter:
  image: prom/node-exporter:latest
  container_name: node-exporter
  restart: unless-stopped
  labels:
    service.discovery.prometheus: "true"
  annotations:
    service.annotations.prometheus.io/scrape: "true"


For Docker Compose versions below v3.8:

The annotations section isn't supported. You can achieve the same functionality using environment variables:

YAML
node-exporter:
  image: prom/node-exporter:latest
  container_name: node-exporter
  restart: unless-stopped
  labels:
    service.discovery.prometheus: "true"
  environment: 

- WEB_SCRAPE_TARGET=true # Adjust the variable name based on node- 

2024년 5월 16일 목요일

Error: 'sharp' is required to be installed in standalone mode for the image optimization to function correctly

 nextjs 12.3.4버전

 standalone 모드로 빌드 후 도커에서 실행시 발생한 에러 

https://github.com/vercel/next.js/issues/59516 참조

최초 sharp 버전 : 0.33.3 을 버전 : 0.32.6 으로 다운 그레이드


2024년 5월 3일 금요일

docker-credential-helper 설치

 rocky linux

gpt에게 문의 했을때 

1. docker-credential-helpers 패키지 설치

Docker의 credential helper를 설치하려면 패키지를 추가로 설치해야 합니다. Rocky Linux에서는 다음과 같이 설치할 수 있습니다.

bash
sudo dnf install docker-credential-helpers

이 패키지에는 다양한 Docker credential helpers가 포함되어 있습니다. 설치 후 다시 확인하세요.

>>실행 후

sudo dnf install docker-credential-helpers

Last metadata expiration check: 0:00:31 ago on Fri 03 May 2024 02:32:46 PM KST. No match for argument: docker-credential-helpers Error: Unable to find a match: docker-credential-helpers

다시 문의

Rocky Linux에서 "docker-credential-helpers" 패키지를 찾을 수 없는 경우, 해당 패키지가 공식 리포지토리에서 제공되지 않을 수 있습니다. 이 경우 docker-credential-pass를 직접 설치해야 합니다. 다음은 이 문제를 해결하기 위한 몇 가지 방법입니다.

1. docker-credential-pass 직접 설치

docker-credential-pass를 직접 설치하려면 GitHub에서 소스 코드를 가져와서 컴파일하는 방법을 사용할 수 있습니다. 이를 위해서는 Golang이 필요합니다. 이 과정은 몇 가지 단계를 포함합니다.

  1. Golang 설치 Rocky Linux에서 Golang을 설치합니다.

    bash
    sudo dnf install golang
  2. Git 설치 Git를 사용하여 소스 코드를 클론하기 위해 Git가 필요합니다.

    bash
    sudo dnf install git
  3. Docker Credential Helper 저장소 클론 GitHub에서 Docker Credential Helper 소스 코드를 클론합니다.

    bash
    git clone https://github.com/docker/docker-credential-helpers.git
  4. 컴파일 및 설치 docker-credential-helpers 디렉토리로 이동하여 pass를 컴파일하고 설치합니다.

    bash
    cd docker-credential-helpers/pass go build

    이제 docker-credential-pass 실행 파일이 생성됩니다. 이 파일을 시스템 경로에 배치해야 합니다.

  5. 실행 파일 시스템 경로에 복사 docker-credential-pass를 /usr/local/bin 또는 시스템의 다른 PATH에 복사합니다.

    bash
    sudo cp docker-credential-pass /usr/local/bin/

2. Docker 재시작

docker-credential-pass 설치 후, Docker를 재시작합니다.

bash
sudo systemctl restart docker

3. PATH 변수 확인

설치한 docker-credential-pass가 올바른 경로에 있는지 확인합니다.

bash
which docker-credential-pass

이 명령어가 /usr/local/bin/docker-credential-pass 또는 유사한 경로를 반환해야 합니다. 이제 Docker의 config.json에서 설정한 credsStore 값에 따라 pass를 사용할 수 있습니다.

위의 단계를 따라 docker-credential-pass를 설치하고 오류를 해결할 수 있습니다. 다시 시도하여 문제가 해결되었는지 확인하세요.

>> git에서 clone 후 docker-credential-helpers/pass 경로로 이동후 go build 실행

>> 아무런 메세지 없음 >> https://github.com/docker/docker-credential-helpers 이동 메뉴얼 확인

Use make to build the program you want. That will leave an executable in the bin directory inside the repository.

$ make osxkeychain

3 - Put that binary in your $PATH, so Docker can find it.

$ cp bin/build/docker-credential-osxkeychain /usr/local/bin/

그렇다. make로 빌드 해야 한다.

나는 pass를 사용할 것이기 때문에 make pass 명령어 실행
cd bin/build/



있다!!

이제 다시 하라는 대로 /usr/local/bin 폴더로 복사


bash
cp cp bin/build/docker-credential-pass /usr/local/bin/

도커로 로그인 시도 했으나

WARNING! Using --password via the CLI is insecure. Use --password-stdin. Error saving credentials: error storing credentials - err: exec: "docker-credential-pass": executable file not found in $PATH, out: ``

경로에 실행가능한 파일이 없단다...뭐지???


복사하면서 권한이 바꼈나 보다.

실행권한 넣어주고

chmod 764 docker-credential-pass

도커로 다시 로그인 시도.
docker login




성공! 이제 이미지 배포하러 가봐야 겠다.