MacOS vnc command line

ssh 접속으로 vnc 모드를 활성화할 필요가 있습니다.

모든 유저를 대상

sudo /System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart \
  -activate -configure -access -on \
  -configure -allowAccessFor -allUsers \
  -configure -restart -agent -privs -all

Continue reading

Python MSS 스크린샷

설치하기

터미널에 아래와 같이 입력후 설치를 합니다.

python -m pip install mss

설치된 모듈이 정상적인지 확인합니다.

import  mss

이미지 처리를 위해서 이미지 처리 모듈을 설치 합니다.

python -m pip install Pillow

스크린샷 만들기

import mss

with mss.mss() as mss_instance:
    monitor_1 = mss_instance.monitors[1]capture
    screenshot = mss_instance.grab(monitor_1)

스크린샷 보기

from PIL import Image
import mss

with mss.mss() as mss_instance:
    monitor_1 = mss_instance.monitors[1]
    screenshot = mss_instance.grab(monitor_1)

    img = Image.frombytes("RGB", screenshot.size, screenshot.bgra, raw", "BGRX")  # Convert to PIL.Image
    img.show()

저장하기

import mss

output_filename = 'screenshot.png'

with mss.mss() as mss_instance:
    mss_instance.shot(output=output_filename)

File Object 로 저장

import io
from PIL import Image
import mss

bytes_io = io.BytesIO()

with mss.mss() as mss_instance:
    monitor_1 = mss_instance.monitors[1]
    screenshot = mss_instance.grab(monitor_1)

    img = Image.frombytes("RGB", screenshot.size, screenshot.bgra, "raw", "BGRX")
    img.save(bytes_io, "PNG")

Continue reading

Python boto3 복사, 업로드, 동기화 유용한 기능

python boto3 라이브러리로 aws 관련 기능들이 필요하여 가장 중요한 기능들을 정리해 보았습니다. 많은 기능들 중에 아마 upload, copy, invalidation이 가장 많을텐데요. 구글링을 하여 제 입맛에 맞도록 수정하여 정리 하였습니다.

Copy folder

동일 버킷, 혹은 다른 버킷으로 파일 및 폴더를 복사 하는 예제입니다. s3://aws_bucket/folderA/folderB/000 의 폴더를 folderA/folderB/1111 로 복사를 한다면,

아래의 예제처럼 작성 할 수 있습니다.

import boto3

s3 = boto3.resource('s3')
src_info = "folderA/folderB/0000"
dst_info = "folderA/folderB/1111"

s3_bucket = s3.Bucket('aws_bucket')

for obj in s3_bucket.objects.filter(Prefix=src_info):
	old_source = {'Bucket': 'aws_bucket', 'Key': obj.key}
	new_key = obj.key.replace(src_info, dst_info, 1)
	print(f"Copy {obj.key} -> {new_key}")
	new_obj = s3_bucket.Object(new_key)
	new_obj.copy(old_source)

Upload folder

boto3 라이브러리에서 폴더를 업로드하는 기능은 지원하지 않아 새로 구현이 필요합니다.

하위 폴더의 재귀적인 호출은 하지 않고 1뎁스 깊이만 폴더 업로드를 지원하는 예제입니다.

import boto3
import os

def upload_dir(profile_name, local_directory, bucket, destination):
    if(False == os.path.isdir(local_directory)):
        return False

    session = boto3.Session(profile_name=profile_name)
    s3_client = session.client('s3')

    for root, dirs, files in os.walk(local_directory):
        for filename in files:
            local_path = os.path.join(root, filename)
            relative_path = os.path.relpath(local_path, local_directory)

            s3_path = f"{destination}/{filename}"

            try:
                print(f"Uploading {s3_path}")
                s3_client.upload_file(local_path, bucket, s3_path, ExtraArgs={
                                      'ACL': 'public-read'})
            except ClientError as e:
                print(e)
                return False

    return True

Upload File

가장 많이 사용되는 파일 업로드 기능입니다.

import boto3

def upload_file(profile_name, file_name, bucket, object_name=None):

    if object_name is None:
        object_name = file_name

    session = boto3.Session(profile_name=profile_name)
    s3_client = session.client('s3')

    try:
        print(f"Uploading  {object_name}")
        response = s3_client.upload_file(
            file_name, bucket, object_name, ExtraArgs={'ACL': 'public-read'})
    except ClientError as e:
        print(e)
        return False
    return True

Cloudfront Invalidation

DistributionId 는 미리 생성이 필요합니다.

import boto3

def wait_invalidation(dist_id, files):
    client = boto3.client('cloudfront')

    response = client.create_invalidation(DistributionId=dist_id,
                                          InvalidationBatch={
                                              'Paths': {
                                                  'Quantity': len(files),
                                                  'Items': ['/{}'.format(f) for f in files]
                                              },
                                              'CallerReference': 'my-references-{}'.format(datetime.datetime.now())})

    invalidation_id = response['Invalidation']['Id']
    waiter = client.get_waiter('invalidation_completed')
    waiter.wait(DistributionId=dist_id,
                Id=invalidation_id,
                WaiterConfig={
                    'Delay': 300,
                    'MaxAttempts': 30
                })

    return

Continue reading

C++ std::vector to std::string

가끔 vector의 내용을 콤마 로 구분된 출력을 하고 싶을 때가 종종 발생한다.

std::vector to std::string

#include <vector>
#include <string>
#include <algorithm>
#include <sstream>
#include <iterator>
#include <iostream>


int main()
{
  std::vector<int> vec;
  vec.push_back(1);
  vec.push_back(4);
  vec.push_back(7);
  vec.push_back(4);
  vec.push_back(9);
  vec.push_back(7);

  std::ostringstream oss;

  if (!vec.empty())
  {
    
    std::copy(vec.begin(), vec.end()-1,
        std::ostream_iterator<int>(oss, ","));
    
    oss << vec.back();
  }

  std::cout << oss.str() << std::endl;
}

std::vector to std::wstring

#include <vector>
#include <string>
#include <algorithm>
#include <sstream>
#include <iterator>
#include <iostream>

int main()
{
  std::vector<int> vec;
  
  vec.push_back(1);
  vec.push_back(4);
  vec.push_back(7);
  vec.push_back(4);
  vec.push_back(9);
  vec.push_back(7);

  std::wostringstream oss;

  if (!vec.empty())
  {
    // Convert all but the last element to avoid a trailing ","
    std::copy(vec.begin(), vec.end()-1,
        std::ostream_iterator<int, wchar_t, std::char_traits<wchar_t> >(oss, L","));

    // Now add the last element with no delimiter
    oss << vec.back();
  }

  std::wcout << oss.str() << std::endl;
}

http://cpp.sh/45sy32

Continue reading

Thread Pool

스레드풀 소스 코드

#include <chrono>
#include <condition_variable>
#include <cstdio>
#include <functional>
#include <future>
#include <mutex>
#include <queue>
#include <thread>
#include <vector>

class ThreadPool
{
	enum class ThreadState
	{
		NONE = -1,
		TERMINATE = 0,
		WAIT_PAUSED = 1,
		PAUSED = 2,
		SLEEPING = 3,
		BUSY = 4,
		AWAITING = 5,
	};

	using AsyncQueue = std::queue<std::function<void()>>;
public:

	ThreadPool();
	virtual ~ThreadPool()
	{
		if (m_state != ThreadState::TERMINATE)
		{
			Stop();
		}
	}

	void Initialize(int init_thd)
	{
		m_workers.reserve(init_thd);

		m_state = ThreadState::BUSY;

		for (auto i = 0; i < init_thd; ++i)
		{
			m_workers.emplace_back([this]() { this->WorkerUpdate(); });
		}
	}
	void Stop()
	{
		m_state = ThreadState::TERMINATE;
		m_cond.notify_all();

		for (auto &w : m_workers)
		{
			w.join();
		}
	}
	// 모든 워커 스레드를 일시정시 시킨다.
	void PauseWorker()
	{
		m_state = ThreadState::PAUSED;
		m_cond.notify_all();
	}

	// 모든 워커 스레드를 재가동 한다.
	void ResumeWorker()
	{
		m_state = ThreadState::BUSY;
	}

	void WorkerUpdate()
	{
		while (m_state != ThreadState::TERMINATE)
		{

			if (m_state == ThreadState::PAUSED)
			{
				while (m_state == ThreadState::PAUSED)
				{
					std::this_thread::sleep_for(std::chrono::milliseconds(200));
				}
			}

			std::unique_lock<std::mutex> lock(m_job_lock);

			m_cond.wait(lock, [this]() {return !this->m_jobs.empty() || m_state == ThreadState::TERMINATE || m_state == ThreadState::PAUSED; });

			if (m_state == ThreadState::PAUSED)
				continue;

			if (m_state == ThreadState::TERMINATE)
				break;

			auto job = std::move(m_jobs.front());
			m_jobs.pop();
			lock.unlock();

			std::chrono::system_clock::time_point begin_time = std::chrono::system_clock::now();

			job();

			auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - begin_time).count();

		}
	}
	ThreadState GetState() { return m_state; }

	template< class F, class ... Args>
	std::future<std::invoke_result_t<F, Args...>> InsertToThread(F f, Args... args);

private:
	std::atomic<ThreadState> m_state = ThreadState::NONE;
	std::condition_variable m_cond;
	std::vector<std::thread> m_workers;
	AsyncQueue m_jobs;
	std::mutex m_job_lock;
};

template< class F, class ... Args>
std::future<std::invoke_result_t<F, Args...>>
ThreadPool::InsertToThread(F f, Args... args)
{
	if (m_state == ThreadState::TERMINATE)
	{
		throw std::runtime_error("ThreadPool was terminated.");
	}

	using return_type = std::invoke_result_t<F, Args...>;

	auto job = std::make_shared<std::packaged_task<return_type()>>(std::bind(f, args...));

	std::future<return_type> job_result_future = job->get_future();
	{
		std::lock_guard<std::mutex> lock(m_job_lock);
		m_jobs.push([job]() { (*job)(); });
	}
	m_cond.notify_one();

	return job_result_future;

}

// 사용 예시
int work(int t, int id) {
	printf("%d start \n", id);
	std::this_thread::sleep_for(std::chrono::seconds(t));
	printf("%d end after %ds\n", id, t);
	return t + id;
}

int main() {
	ThreadPool pool(3);

	pool.Initialize(3);

	std::vector<std::future<int>> futures;
	for (int i = 0; i < 10; i++) {
		futures.InsertToThread(pool.EnqueueJob(work, i % 3 + 1, i));
	}
	for (auto& f : futures) {
		printf("result : %d \n", f.get());
	}
}

Continue reading

C++ split

C++ 에서 간단하게 문자열 파싱하기

#include <iostream>
#include <string>
#include <sstream>

int main()
{
    std::wstring text;
    std::wstring data = L"000;123;333";
    
    std::wistringstream token_stream(data.c_str());
    
	while (std::getline(token_stream, text, L';'))
	{
		if (!text.empty())
		{
		    std::wcout << text << std::endl;
		}
	}
}

문자열로 파싱하기


#include <iostream>
#include <string>

int main()
{
    std::string s = "scott>=tiger>=mushroom";
    std::string delimiter = ">=";

    size_t last = 0;
    size_t next = 0; 
    while ((next = s.find(delimiter, last)) != std::string::npos) 
    { 
        std::cout << s.substr(last, next-last) << std::endl; 
        last = next + delimiter.length(); 
    } 
    std::cout << s.substr(last) << std::endl;
}

Continue reading

Synology nas에서 docker를 이용한 jekyll 사용하기

Synology Jekyll Docker

github.io 도 있지만 개인 보유하고 있는 Nas 를 이용해서 개인 블러그를 운영을 위해서 작성합니다. 하루 종일 이것 저것 삽질하면서 잘 안되 포기 할까도 생각했지만 오기 발동하여 결국 성공!! Jekyll Docker 의 문서에 아주 잘 나와 있는데 Synology 에서 적용 한다고 삽질을….

https://github.com/envygeeks/jekyll-docker/blob/master/README.md

간략히 내용을 정리 해보면, jekyll_home 생성 후 bundle 파일을 저장하기 위한 커스텀 폴더 생성 jekyll bundle update 를 실행하여 필요한 bundle 파일을 업데이트 후 -w 옵션을 이용한 변경 감지를 통해서 자동 정적 페이지 생성을 한다. 입니다.

Docker 저장소에서 jekyll 검색한후 jekyll/jekyll 이미지를 다운로드 합니다.

jekyll 의 원본이 위치한 경로의 접근 권한을 everyone 으로 읽기쓰기가 가능 하도록 먼저 설정합니다. 실행권한을 최고 권한으로 실행했지만 결국은 권한이 없다고 에러가.. 꼭! everyone 으로 읽기 쓰기를 설정하세요.

저는 jekyll_home 공유 폴더를 생성 후 이미 theme 를 생성한 폴더와 파일을 준비 하였습니다. 이 부분은 여기서 다루지 않을 예정입니다.

1565786005518

Dependencies

jekyll Docker Gemfile 의 리스트에서 의존성 파일을 설치 하게 됩니다.

Updatding & Caching

jekyll_home/vendor/bundle 폴더는 생성해주세요. Gemfile 을 제공한다면, 아래와 같이 실행 합니다.

docker run --rm \
  --volume="/volume1/jekyll_home:/srv/jekyll" \
  --volume="/volume1/jekyll_home/vendor/bundle:/usr/local/bundle" \
  -it jekyll/jekyll:3.8.6 \
  bundle update

필요한 파일을 자동으로 다운로드 하여, vendor/bundle 폴더에 필요한 파일을 자동으로 다운을 시작합니다. 이부분을 저는 잘 이해를 못해서 하루 삽질했네요.

1565786178287

/jekyll_home/vendor/bundle 폴더에는 아래와 같이 폴더와 파일이 생성된것 을 확인 할 수 있습니다.

1565786244229

Build(생성하기)

이제 정적 페이지를 생성 하기 위해서는 bundle 에 캐싱한 내용을 이용하여 아래의 명령을 실행하면, jekyll_home/_site 폴더가 생성되고 정적 파일들이 생성되는 것을 확인 할 수 있습니다.

최신 버전의 jekyll 에서는 bundle install 시 번들 경로가 문제가 될수 있습니다.

docker run --rm \
  --volume="/volume1/jekyll_home:/srv/jekyll" \
  --volume="/volume1/jekyll_home/vendor/bundle:/usr/local/bundle" \
  -it jekyll/jekyll:3.8.6 \
  jekyll build

_post 폴더의 변경된 내용을 자동으로 감지후 페이지 생성을 위해서는 synology 에서 Docker 이미지를 실행하여 자동으로 생성 하도록 하면 됩니다.

Synology Docker 를 이용하여 자동 변경 감지 후 자동 생성하자

이미지를 클릭 후 실행 버튼을 클릭하여 컨테이너를 생성 하도록 합니다.

1565784898282

컨테이너 이름은 적당한 이름을 작성하고 고급 설정을 클릭하여 , 캐싱한 bundle 경로와 jekyll 문서가 있는 루트 경로를 볼륨으로 추가합니다.

1565785185185

볼륨 추가

1565785216697

환경 설정 탭에서 실행명령 란에 jekyll build -w 을 입력후 적용 버튼 누릅니다.

1565785292831

모든게 완료 되었다면 jekyll_home/_site 폴더가 생성된 후 정적페이지를 위한 파일들이 자동 생성 됨을 확인 할 수 있습니다.

Continue reading

adb를 이용하여 hosts 파일 수정

adb를 이용하여 에뮬레이터의 /system/etc/hosts 파일을 수정해보자

먼저 실행중인 에뮬레이터 확인이 필요합니다.

adb devices

1544029819446

  • 디바이스 마운트
adb -s {에뮬레이터_이름} remount

1544030062681

  • 루트권한으로 변경
adb root
adb remount

1544030093765

  • hosts 파일 다운로드
adb -s {에뮬레이터_이름} pull /system/etc/hosts {다운경로}

1544030115013

  • hosts 파일 수정

메모장혹은 다른 파일 에디터를 이용하여 수정을 한다.

  • hosts 파일 업로드
adb -s {에뮬레이터_이름} push {수정한_hosts} /system/etc/hosts

1544030148494

  • 업로드 확인
adb shell
cat /etc/hosts
ping {호스트}

Continue reading

Pagination


© 2018. by brian jung

Powered by storm