6-2. 폴더 명 역시 바꾸어주고, first_main 폴더(구 algo 폴더) 안의 main.cpp의 타겟이 first_main product로 잘 선택되어있는지 확인합니다.
6-3. 위에 있는 Run에는 여전히 algo로 떠있습니다. 이대로 실행을 할 경우에는 algo에서 first_main으로 target명만 바꾼 것이기 때문에 first_main > main.cpp를 새로 작성하고 재 컴파일을 해도 올바르게 컴파일이 됩니다. 하지만, 나중에 헷갈릴 가능성이 있기 때문에 run을 위해 사용하는 Target이름 명 역시 바꾸어 주기 위해 Run 옆에 있는 Target 선택에서 Manage Schemes를 클릭합니다.
6-4. Manage Scheme에서 실행할 Target들을 관리할 수 있습니다. 여기에서 - 를 이용하여 기존의 algo라는 이름의 scheme를 지워주고 + 를 first_main이라는 이름으로 schemes에 target을 추가해 줍니다.
7. 실행을 합니다! 이때 왼쪽 상단에서 어떤 Target으로 실행을 할지를 선택해주면, 알고리즘용으로 여러개의 main을 한개의 프로젝트에서 작동시킬 수 있습니다.
여기까지 Xcode로 여러개의 main.cpp 파일을 만들어야할 때 방법입니다. 알고리즘을 cpp로 풀고, git으로 한 폴더에 관리하려다 보니까 환경을 세팅하다보니까 이렇게 포스팅까지 하게되었습니다 :) 혹시 더 좋은 꿀팁이 있다면 댓글 달아주세요 감사합니다.
When solving problems on Baekjoon Online Judge or LeetCode, you often need to create and run multiple solution.cpp or main.cpp files. I'm going to show you how to create multiple main.cpp files in a single Xcode project.
1. Create a new Xcode project. Make sure to select Command Line Tool when creating the project.
2. Fill in the options for the new project.
3. Click on the Xcode project.
4. At the bottom of the project, you'll see a bar listing the project and targets. At the bottom of that bar, there are + and - buttons. Click the + button to create a new Target.
Just like in steps 1–2, select Command Line Tool for the Target and specify a Product Name to create it.
5. Now you can see that two main files have been created.
6. For convenience, I'll rename the folder and Products name of the first Target to first_main. Click the expand toggle for the detailed steps
6-1. Double-click the algo target under Targets in the Xcode project to rename it.
6-2. Rename the folder as well, then check that the main.cpp inside the first_main folder (formerly the algo folder) has its target correctly set to the first_main product.
6-3. The Run button at the top still shows algo. If you run it as-is, it will still compile correctly since you only changed the target name from algo to first_main — even if you rewrite first_main > main.cpp and recompile. However, to avoid confusion later, let's also rename the Target used for running. Click on the Target selector next to Run and select Manage Schemes.
6-4. In Manage Schemes, you can manage the Targets available for running. Here, use the - button to remove the old scheme named algo, then use the + button to add a target to the schemes with the name first_main.
7. Run it! Just select which Target to run from the top-left corner, and you can run multiple main files for algorithm problems within a single project.
And that's how you handle multiple main.cpp files in Xcode. I ended up writing this post while setting up my environment to solve algorithm problems in C++ and manage them in a single folder with git :) If you have any better tips, please leave a comment. Thanks!
<!DOCTYPE html>
<html>
<head>
<script>
/* code will go here */
</script>
</head>
<body>
<h1>Image Styling with Web Components</h1>
<!-- elements will go here -->
</body>
</html>
1-2. 나의 첫번째 Custom Element 만들기
이미지를 이 페이지로 드래그앤 드롭을 하기 위한 코드를 작성해 보자. <codelab-dragdrop></codelab-dragdrop> 태그를 생성할 예정이며, 이 태그는 파일이 드롭되는 위치를 표시하는 곳을 나타낼 것이다.
이에 대한 로직은 Javascript를 이용하여 구현할 예정이다. 1. 새로운 element를 정의 2. element를 사용(인스턴스 화)
<codelab-dragdrop></codelab-dragdrop>
1-3. Element 정의
Custom Element는 HTMLElement라는 ES6의 클래스를 상속받은 것 이다.
ES6는 ECMAScript6의 줄임말으로 ECMAScript6는 자바스크립트 표준 단체인 ECMA가 제정하는 자바스크립트 표준이다.
자바스크립트는 프로토타입 기반(prototype-based) 객체지향 언어다. 프로토타입 기반 프로그래밍은 클래스가 필요없는(class-free) 객체지향 프로그래밍 스타일로 프로토타입 체인과 클로저 등으로 객체 지향 언어의 상속, 캡슐화(정보 은닉) 등의 개념을 구현할 수 있다.
ES6의 클래스는 기존 프로토타입 기반 객체지향 프로그래밍보다 클래스 기반 언어에 익숙한 프로그래머가 보다 빠르게 학습할 수 있는 단순명료한 새로운 문법을 제시하고 있다. 그렇다고 ES6의 클래스가 기존의 프로토타입 기반 객체지향 모델을 폐지하고 새로운 객체지향 모델을 제공하는 것은 아니다. [출처] https://poiemaweb.com/es6-class
<script> 태그안에 Javascript 문법을 이용해서 나의 Custom Element를 정의한다.
/* code will go here */
class CodelabDragdrop extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
// we'll do stuff here later
console.info('Element connected!');
}
}
customElements.define('codelab-dragdrop', CodelabDragdrop);
connectedCallback() : document의 DOM에 정의한 custom element가 맨 처음 호출되었을 때 실행된다. customElements.defind(DOMString, class, {extends:'[tag-name]'}) - DOMString : 사용자가 element에 전달하려는 이름 (즉, 태그 네임). 이때 커스텀 엘리먼트의 이름들은 dash('-')가 포함된 이름을 사용해야하므로 주의해야한다! - class : element의 행위가 정의된 object이다. - extends (optional) : 상속받을 태그를 지정할 수 있다. 만약 { extends: 'p'} 이렇게 지정한다면, p 태그의 inline 성질을 갖고있는 객체가 되는 듯
개발자도구( option+command+i / F12 )를 이용해서 확인해보면 connection이 완료되었다는 메세지를 확인 할 수 있다.
2. Drag and Drop
2-1. Target 생성하기
<!-- elements will go here -->
<codelab-dragdrop>
<div style="width: 200px; height: 200px; background: red;">
</div>
</codelab-dragdrop>
페이지를 새로 고침하면 큰 빨간색 상자가 나타난다. 더 중요한 것은 페이지를 개발자 도구로 확인하면codelab-dragdrop 내부에 빨간색 사각형을 보유하고 있기 때문에 현재 200 x 200 픽셀의 크기를 갖고있음을 알 수 있다.
2-2. Handler 추가하기
codelab-dragdrop에 파일을 끌어다 놓을 수 있도록확장 해보자.
Web component가 가진 기능중에 하나는 캡슐화이다. 이를 수행할 수 있는 방법은 element defind 안에 코드를 추가하는 것이다. 이전에 작성한 ES6 클래스의 constructor element 자체에 리스너를 추가하여 메소드를 업데이트 할 것이다.
constructor() {
super(); // you always need super
this.addEventListener('dragover', (ev) => {
ev.preventDefault();
});
this.addEventListener('drop', (ev) => {
ev.preventDefault();
const file = ev.dataTransfer.files[0] || null;
file && this._gotFile(file);
});
}
super()는 항상 필요하다. Web Element와 관련한 클래스인 HTMLElement 클래스를 상속받고, 그 기능을 온전히 사용하기 위해서.
여기서 드래그 앤 드롭과 관련된 두 가지 이벤트를 처리합니다. 여기서 중요한 것은 drop 핸들러이다. 첫 번째 파일 (있는 경우)을 드래그하여 _getFile() 이라는 메소드를 호출하게 되어있다.
2-3. Event 방출하기
이 코드랩의 목표는 Image를 조작할 수 있는 것(조작기 - manipulator)을 만드는 것이다. 따라서 우리는 이미지를 만들고, 해당하는 조작기에 이미지를 넘겨주는 것을 목적으로 한다.
이 작업을 수행할 일반 인터페이스를 제공하는 가장 좋은 방법은 HTML 자체를 이용해서 우리가 사용 가능할 수 있게 하는 것이다. 이전 단계의 drop과 같이 event를 생성해 볼 것이다. drop된 파일에서 하나의 유효한 이미지를 생성하는 것 같이 이 이벤트는 우리의 목표에 맞게 구체적으로 설정되어있다. (추가하면 더 많은 작업을 할 수 있다 - 예 : 이미지의 크기를 먼저 조정한 다음 보낼 수 있다.)
이 코드에서 보는 것처럼 _getFile() 이라는 메소드를 작성한다. 이것은 File을 하나의 Image로 Load하며, custom한 Image로 방출한다.
_gotFile(file) {
const image = new Image();
const reader = new FileReader();
reader.onload = (event) => {
// when the reader is ready
image.src = event.target.result;
image.onload = () => {
// when the image is ready
const params = {
detail: image,
bubbles: true,
};
const ev = new CustomEvent('image', params);
this.dispatchEvent(ev);
};
};
reader.readAsDataURL(file);
}
reader가 준비가 된 경우, image객체의 src(경로) 속성에 drop 이벤트를 받은 타겟인 image의 결과값을 저장한다. 그렇게 해서 image가 준비가 잘 되었을 경우에 param이라는 변수를 정의하는데 이때 detail과 bubbles라는 속성을 지정하며. 우리가 image가 잘 들어왔는지 확인을 하기 위해서 CustomEvent라는 객체를 새로 생성한다. this.dispatchEvent(ev) : 적어도 하나의 이벤트 핸들러가 해당하는 이벤트를 처리하면서 이 메소드를 호출했다면 false를 반환하고, 그렇지 않으면 true를 반환한다.
마지막으로 이 element를 codelab-dragdrop element 안에 넣는다. 이때 이전에 있던 빨간색 상자는 제거한다. 이제 codelab-effect element가 target image를 제공하는 데 도움이 된다.
<!-- elements will go here -->
<codelab-dragdrop>
<codelab-effects></codelab-effects>
</codelab-dragdrop>
3-3. Putting It Together
이전 단계에 개발자 도구를 이용해서 event를 확인하려고 넣었던 스크립트를 기억하는가? 이 스크립트를 이용해서 이벤트를 연결해 보자!
<!-- elements will go here -->
<codelab-dragdrop id="dragdrop">
<codelab-effects id="effects"></codelab-effects>
</codelab-dragdrop>
<script>
dragdrop.addEventListener('image', (ev) => {
effects.image = ev.detail; // set the image that we got in dragdrop
});
</script>
이제 image 이벤트가 발생하면(즉 image를 drop 했다는 이벤트가 발생하면) codelab-effects 요소에 있는 image 속성을 설정하도록 코드가 장성되어있다. 이제 이렇게 제공한 이미지의 픽셀 데이터를 가져오는 것을 코드에 추가해 보자.
constructor() {
super();
this.root = this.attachShadow({mode: 'open'});
// Leave the root.innerHTML part alone
}
// Add this method
set image(image) {
const canvas = this.root.getElementById('canvas');
// resize image to something reasonable
canvas.width = Math.min(1024, Math.max(256, image.width));
canvas.height = (image.height * (canvas.width / image.width));
// clone buffer to get one of same size
const buf = canvas.cloneNode(true);
const ctx = buf.getContext('2d');
ctx.drawImage(image, 0, 0, buf.width, buf.height);
this.data = ctx.getImageData(0, 0, buf.width, buf.height).data;
console.info(this.data);
}
setter는 클래스 필드에 값을 할당할 때마다 클래스 필드의 값을 조작하는 행위가 필요할 때 사용한다. setter는 메소드 이름 앞에 set 키워드를 사용해 정의한다. 이때 메소드 이름은 클래스 필드 이름처럼 사용된다. 다시 말해 setter는 호출하는 것이 아니라 프로퍼티처럼 값을 할당하는 형식으로 사용하며 할당 시에 메소드가 호출된다.
이제 이 곳에 이미지를 Drag and Drop 하면 해당하는 이미지의 픽셀 데이터를 console에서 확인 할 수 있다.
3-4. 기본 스타일링
console.log()를 이용해서 데이터 숫자값만 보기 보다는 데이터를 가져와서 실제 캔버스로 그리는 작업을 해보자. set image 메서드 내부에서 만든 이미지 데이터를 보고 캔버스에 그린다. 이 코드랩은 캔버스 사용 및 이미지 데이터 작업에 관한 것이 아니라 웹 구성 요소를 시연하는데 도움이 되며 흥미로운 효과를 기대할 수 있다.
// Replace console.info with:
this.draw();
}
// And add this method
draw() {
const canvas = this.root.getElementById('canvas');
canvas.width = canvas.width; // clear canvas
const context = canvas.getContext('2d');
const amount = +this.root.getElementById('amount').value;
const size = amount * .8;
for (let y = amount; y < canvas.height; y += amount * 2) {
for (let x = amount; x < canvas.width; x += amount * 2) {
const index = ((y * canvas.width) + x) * 4;
const [r,g,b] = this.data.slice(index, index+3);
const color = `rgb(${r},${g},${b})`;
context.beginPath();
context.arc(x, y, size, 0, 360, false);
context.fillStyle = color;
context.fill();
}
}
}
페이지를 새로 고침하고 좋아하는 이미지를 페이지로 드래그하면 점묘 효과가 나타난다.
4.Saving Images
4-1. Click To Download
방금 만든 점묘화의 이미지를 공유하거나 사용하기 위해서는 마우스 오른쪽 버튼을 클릭해서 이미지를 다운로드 해야한다. 대신 canvas 아래에 링크를 추가하여 이미지를 자동으로 다운로드를 할 수 있도록 환경을 만들어 볼 예정이다.
그리고 이 link라는 id값을 받아서 download 할 수 있도록 이벤트 핸들러를 설정한다.
// And add this handler
const link = this.root.getElementById('link');
link.addEventListener('click', (ev) => {
link.href = this.root.getElementById('canvas').toDataURL();
link.download = 'pointify.png';
});
다운로드 완료!!
5. Control 추가
5-1. 응답하기
"AMOUNT" 슬라이더를 활용해보자! 이 것을 활용해서 우리가 그리는 점묘화의 점의 크기를 제어할 수 있다. 그러나 현재는 이미지 자체가 드롭될 때 한번만 발생하기 때문에 코드를 수정해보자
CodeLabEffects 클래스의 생성자 안에 리스너를 추가해 보자. 다시 리마인드 하면 이것은 this.root는 AMOUNT 슬라이더를 포함한 모든 Shadow DOM이 있는 곳이다. 이것은 Shadow DOM element에 의해 생긴 모든 변경에 응답하고 draw 메소드를 호출한다.
...
link.download = 'pointify.png';
});
//add these two new listeners
this.root.addEventListener('input', (ev) => this.draw());
this.root.addEventListener('change', (ev) => this.draw());
}
input이나 change와 관련한 이벤트가 들어왔을 경우에 draw()를 다시 실행한다.
draw() {
const canvas = this.root.getElementById('canvas');
canvas.width = canvas.width; // clear canvas
const context = canvas.getContext('2d');
const attenuation = this.root.getElementById('attenuation').checked;
const amount = +this.root.getElementById('amount').value;
const size = this.root.getElementById('size').value * amount;
const opacity = this.root.getElementById('opacity').value;
for (let y = amount; y < canvas.height; y += amount * 2) {
for (let x = amount; x < canvas.width; x += amount * 2) {
const index = ((y * canvas.width) + x) * 4;
const [r,g,b] = this.data.slice(index, index+3);
const color = `rgba(${r},${g},${b},${opacity})`;
const weight = 1 - ( this.data[ index ] / 255 );
const radius = (attenuation ? size * weight : size);
context.beginPath();
context.arc(x, y, radius, 0, 360, false);
context.fillStyle = color;
context.fill();
}
}
}
size : 원의 기본 반경을 제어한다 opacity : 원의 투명도를 제어한다. attenuation : 각 원의 어두운 정도에 따라 원의 크기를 조정한다.
5-3. 추가 기능
이미지 전체를 색조로 만드는 컬러 필터 다른 모양을 사용 정렬되지 않은 배치 등
이 component element 에는 많은 가능성이 있다!
Polymer와 같은 다양한 Web Component Element 라이브러리도 있다. 이 라이브러리에는 지금 렌더링 수준의 그림 하나하나 생각했던 것과 같은 Low Level의 Component Element보다 좀더 High Level 계층의 추상화된 라이브러리를 제공한다.
This is a summary I put together in Korean to prepare for a codelab seminar.
A new technology that lets you create reusable elements for HTML pages. They have custom user-defined names: you can bundle the tags you want and encapsulate them.
This is the process of creating a WebComponent using Custom Elements (codelab-dragdrop) and shadow DOM (codelab-effects). By combining these, we'll build a website that can manipulate images dragged onto the page.
How to declare Custom Elements
How to add listeners and handlers to a Component
How to create a Shadow Root to encapsulate Custom Design
How to compose multiple components to build a small application
<!DOCTYPE html>
<html>
<head>
<script>
/* code will go here */
</script>
</head>
<body>
<h1>Image Styling with Web Components</h1>
<!-- elements will go here -->
</body>
</html>
1-2. Creating My First Custom Element
Let's write the code for dragging and dropping an image onto this page. <codelab-dragdrop></codelab-dragdrop> — we're going to create this tag, and it will indicate the area where files can be dropped.
The logic for this will be implemented using Javascript. 1. Define a new element 2. Use the element (instantiate it)
<codelab-dragdrop></codelab-dragdrop>
1-3. Defining the Element
A Custom Element is an ES6 class that extends HTMLElement.
ES6 stands for ECMAScript 6. ECMAScript 6 is a JavaScript standard established by ECMA, the JavaScript standards body.
JavaScript is a prototype-based object-oriented language. Prototype-based programming is a class-free object-oriented programming style that can implement concepts like inheritance and encapsulation (information hiding) through prototype chains and closures.
ES6 classes provide a cleaner, simpler syntax that makes it easier for programmers familiar with class-based languages to learn quickly, compared to the traditional prototype-based object-oriented programming. That said, ES6 classes don't replace the existing prototype-based object-oriented model with a new one. [Source] https://poiemaweb.com/es6-class
We define our Custom Element using Javascript syntax inside the <script> tag.
/* code will go here */
class CodelabDragdrop extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
// we'll do stuff here later
console.info('Element connected!');
}
}
customElements.define('codelab-dragdrop', CodelabDragdrop);
connectedCallback(): This is called when the custom element is first inserted into the document's DOM. customElements.define(DOMString, class, {extends:'[tag-name]'}) - DOMString: The name you want to give the element (i.e., the tag name). Note that custom element names must include a dash ('-'), so keep that in mind! - class: An object that defines the element's behavior. - extends (optional): You can specify a tag to inherit from. For example, if you set { extends: 'p'}, the resulting object seems to take on the inline properties of a p tag.
If you check using the developer tools (option+command+i / F12), you can confirm the connection completed message.
2. Drag and Drop
2-1. Creating the Target
<!-- elements will go here -->
<codelab-dragdrop>
<div style="width: 200px; height: 200px; background: red;">
</div>
</codelab-dragdrop>
When you refresh the page, a big red box appears. More importantly, if you inspect the page with developer tools,you can see that the red square is contained inside codelab-dragdrop, so it currently has a size of 200 x 200 pixels.
2-2. Adding Handlers
Let's extend codelab-dragdrop so that files can be dragged and dropped onto it.
One of the features of Web Components is encapsulation. The way to achieve this is by adding code inside the element definition. We'll update the constructor of the ES6 class we wrote earlier by adding listeners to the element itself.
constructor() {
super(); // you always need super
this.addEventListener('dragover', (ev) => {
ev.preventDefault();
});
this.addEventListener('drop', (ev) => {
ev.preventDefault();
const file = ev.dataTransfer.files[0] || null;
file && this._gotFile(file);
});
}
super() is always required — to inherit from HTMLElement, the class related to Web Elements, and to fully use its features.
Here we handle two events related to drag and drop. The important one here is the drop handler. It takes the first file (if there is one) from the drag and calls a method called _getFile().
2-3. Emitting Events
The goal of this codelab is to build something that can manipulate images (a manipulator). So our objective is to create an image and pass it to the corresponding manipulator.
The best way to provide a general interface for this is to make it available to us through HTML itself. Just like the drop event from the previous step, we're going to create an event. Like generating a single valid image from a dropped file, this event is specifically tailored to our goal. (You can do more if you add to it — for example, you could resize the image first before sending it.)
As you can see in this code, we write a method called _getFile(). It loads a File as an Image and emits it as a custom Image event.
_gotFile(file) {
const image = new Image();
const reader = new FileReader();
reader.onload = (event) => {
// when the reader is ready
image.src = event.target.result;
image.onload = () => {
// when the image is ready
const params = {
detail: image,
bubbles: true,
};
const ev = new CustomEvent('image', params);
this.dispatchEvent(ev);
};
};
reader.readAsDataURL(file);
}
When the reader is ready, the result of the drop event target image is stored in the image object's src (path) property. Once the image is successfully loaded, we define a variable called params with detail and bubbles properties. To verify that the image was received correctly, we create a new CustomEvent object. this.dispatchEvent(ev): Returns false if at least one event handler that handled the event called this method, and true otherwise.
If an image is dropped onto the designated area, it shows the image information in the console. This is where the CustomEvent we set up earlier kicks in.
3. Connecting Element
3-1. Creating My Second Custom Element
Let's create a second Custom Element called codelab-effects. This element will render the image and can apply interesting visual effects to it.
Shadow DOM allows you to add custom HTML that isn't actually part of the page's main DOM. The method used to enable Shadow DOM is attachShadow().
Depending on the mode of attachShadow(), you can control whether the HTML code inside the element is visible in the developer tools or not.
It's an element that isn't visible in the actual developer tools, and it can typically be accessed using document.querySelector() or getElementById().
Not every Custom Element needs a Shadow Root. In fact, the <codelab-dragdrop> element performs complex logic for manipulating dropped files without creating a new one. But it's a really powerful API.
You can define a template by adding a few lines of code for the HTML inside the Shadow DOM.
Finally, we place this element inside the codelab-dragdrop element. Remove the red box from before. Now the codelab-effects element helps provide the target image.
<!-- elements will go here -->
<codelab-dragdrop>
<codelab-effects></codelab-effects>
</codelab-dragdrop>
3-3. Putting It Together
Remember the script we pasted in the developer tools to check the event in the previous step? Let's use this script to connect the events!
<!-- elements will go here -->
<codelab-dragdrop id="dragdrop">
<codelab-effects id="effects"></codelab-effects>
</codelab-dragdrop>
<script>
dragdrop.addEventListener('image', (ev) => {
effects.image = ev.detail; // set the image that we got in dragdrop
});
</script>
Now the code is set up so that when an image event fires (i.e., when an image is dropped), it sets the image property on the codelab-effects element. Let's now add code to grab the pixel data from the provided image.
constructor() {
super();
this.root = this.attachShadow({mode: 'open'});
// Leave the root.innerHTML part alone
}
// Add this method
set image(image) {
const canvas = this.root.getElementById('canvas');
// resize image to something reasonable
canvas.width = Math.min(1024, Math.max(256, image.width));
canvas.height = (image.height * (canvas.width / image.width));
// clone buffer to get one of same size
const buf = canvas.cloneNode(true);
const ctx = buf.getContext('2d');
ctx.drawImage(image, 0, 0, buf.width, buf.height);
this.data = ctx.getImageData(0, 0, buf.width, buf.height).data;
console.info(this.data);
}
A setter is used when you need to manipulate the value of a class field every time a value is assigned to it. A setter is defined by placing the set keyword before the method name. The method name is then used as if it were a class field name. In other words, a setter isn't called like a regular method — it's used in the format of assigning a value like a property, and the method is invoked upon assignment.
Now if you drag and drop an image here, you can see the pixel data of that image in the console.
3-4. Basic Styling
Rather than just looking at data numbers via console.log(), let's actually grab the data and draw it on the canvas. We take the image data created inside the set image method and draw it on the canvas. This codelab isn't about working with canvas or image data — it's about demonstrating Web Components, and you can look forward to some interesting effects.
// Replace console.info with:
this.draw();
}
// And add this method
draw() {
const canvas = this.root.getElementById('canvas');
canvas.width = canvas.width; // clear canvas
const context = canvas.getContext('2d');
const amount = +this.root.getElementById('amount').value;
const size = amount * .8;
for (let y = amount; y < canvas.height; y += amount * 2) {
for (let x = amount; x < canvas.width; x += amount * 2) {
const index = ((y * canvas.width) + x) * 4;
const [r,g,b] = this.data.slice(index, index+3);
const color = `rgb(${r},${g},${b})`;
context.beginPath();
context.arc(x, y, size, 0, 360, false);
context.fillStyle = color;
context.fill();
}
}
}
Refresh the page and drag your favorite image onto it — you'll see a pointillism effect appear.
4.Saving Images
4-1. Click To Download
To share or use the pointillism image we just created, you'd have to right-click and download the image. Instead, we're going to add a link below the canvas so that the image can be downloaded automatically.
Then we set up an event handler using the link id to enable the download.
// And add this handler
const link = this.root.getElementById('link');
link.addEventListener('click', (ev) => {
link.href = this.root.getElementById('canvas').toDataURL();
link.download = 'pointify.png';
});
Download complete!!
5. Adding Controls
5-1. Responding to Input
Let's make use of the "AMOUNT" slider! We can use it to control the size of the dots in our pointillism image. But right now, the drawing only happens once when the image is dropped, so let's fix the code.
Let's add a listener inside the constructor of the CodelabEffects class. As a reminder, this.root is where all the Shadow DOM lives, including the AMOUNT slider. This will respond to any changes made by Shadow DOM elements and call the draw method.
...
link.download = 'pointify.png';
});
//add these two new listeners
this.root.addEventListener('input', (ev) => this.draw());
this.root.addEventListener('change', (ev) => this.draw());
}
When an input or change event comes in, it re-executes draw().
The rendering code, draw(), also needs a slight update to accommodate the controls.
draw() {
const canvas = this.root.getElementById('canvas');
canvas.width = canvas.width; // clear canvas
const context = canvas.getContext('2d');
const attenuation = this.root.getElementById('attenuation').checked;
const amount = +this.root.getElementById('amount').value;
const size = this.root.getElementById('size').value * amount;
const opacity = this.root.getElementById('opacity').value;
for (let y = amount; y < canvas.height; y += amount * 2) {
for (let x = amount; x < canvas.width; x += amount * 2) {
const index = ((y * canvas.width) + x) * 4;
const [r,g,b] = this.data.slice(index, index+3);
const color = `rgba(${r},${g},${b},${opacity})`;
const weight = 1 - ( this.data[ index ] / 255 );
const radius = (attenuation ? size * weight : size);
context.beginPath();
context.arc(x, y, radius, 0, 360, false);
context.fillStyle = color;
context.fill();
}
}
}
size: Controls the base radius of the circles. opacity: Controls the transparency of the circles. attenuation: Adjusts the size of each circle based on how dark it is.
5-3. Additional Features
A color filter that tints the entire image Using different shapes Randomized placement, etc.
There are so many possibilities with this component element!
There are also various Web Component element libraries like Polymer. These libraries provide higher-level abstractions rather than the low-level component elements we were working with here, where we had to think about each individual rendering detail.
Mac 적응기 - 커맨드 편 | Mac Adaptation Journey - Command Edition
쟈 미
728x90
Mac Pro를 드디어 샀습니다!! 근데, 윈도우랑 너무 다르다 보니까 아무래도 적응하는데 시간이 걸리더군요! 그래서 각종 커맨드 부터 제가 사용하는 tool 커맨드까지 모두 정리하려 합니다
Mac Command
키보드 키는 기호랑 연결지어서 알면 좋을 것 같습니다 :)
command ⌘ shift ⇧ option ⌥ control ⌃
윈도우랑 매칭 가능
윈도우의 control이 mac의 command와 매칭이 되는 것 같아요! 기본적인 커맨드 입니다.
복사 : ⌘ + c 붙여넣기 : ⌘+ v 잘라내기 : ⌘+ x 되돌리기 : ⌘+ z 전체선택 : ⌘+ a 저장 : ⌘+ s 찾기 : ⌘+ f
윈도우와 매칭이 어려운 커맨드
애플리케이션 닫기 :⌘ + q 탭닫기 : ⌘ + w 파일 삭제 :⌘ + delete 파일 들어가기 & 하위 폴더로 들어가기 : ⌘ + ↓ 상위 폴더로 나가기 :⌘ + ↑ 내 HD내 모든 파일 찾기 : ⌘ + space 전체 캡쳐 : ⌘ + shift+ 3 부분 캡쳐 : ⌘ + shift + 4 캡쳐 선택 : ⌘ + shift + 5
페이지 뒤로가기 : ⌘ + [ 페이지 앞으로가기 :⌘ + ] 창 숨기기 :⌘+ h 창 이동 : ⌃ + 화살표 , 손가락 3개쓸기, ⌘ + tab
텍스트 편집시 유용
한 줄 맨앞 맨뒤 이동 : ⌘ + 화살표 한 단어 맨앞 맨뒤 이동 : ⌃ + 화살표 텍스트 선택 : shift + 화살표 // 응용 : shift + ⌘+ 화살표 , shift +⌃+ 화살표 이모티콘 및 특수문자 입력 :⌃ +⌘ + space
Shell 명령어
shell에서 finder열기 : open .
Intellij Mac Command
preference : ⌘ + , 전체 파일 검색 : ⌘ + shift + f action 검색 : ⌘ + shift + a 연결한 server의 task name 검색 : ⌥ + shift + n
이전에 작업한 커서 위치에서 보기 : ⌘ + [ 이후에 작업한 커서 위치에서 보기 : ⌘ + ]
이전 탭으로 이동하기 : ⌘ + shift + [ 이후 탭으로 이동하기 : ⌘ + shift + ]
줄 자동 정렬 : ⌥ + ⌘ + l
I finally bought a Mac Pro!! But since it's so different from Windows, it definitely took some time to get used to! So I'm going to organize everything from basic commands to the tool commands I personally use.
Mac Command
It's helpful to associate the keyboard keys with their symbols :)
command ⌘ shift ⇧ option ⌥ control ⌃
Matching with Windows
It seems like Windows' control matches up with Mac's command! These are the basic commands.
Copy : ⌘ + c Paste : ⌘+ v Cut : ⌘+ x Undo : ⌘+ z Select All : ⌘+ a Save : ⌘+ s Find : ⌘+ f
Commands Hard to Match with Windows
Quit Application :⌘ + q Close Tab : ⌘ + w Delete File :⌘ + delete Open File & Enter Subfolder : ⌘ + ↓ Go to Parent Folder :⌘ + ↑ Search All Files on HD : ⌘ + space Full Screen Capture : ⌘ + shift+ 3 Partial Capture : ⌘ + shift + 4 Capture Selection : ⌘ + shift + 5
Page Back : ⌘ + [ Page Forward :⌘ + ] Hide Window :⌘+ h Switch Windows : ⌃ + Arrow Keys, Three-Finger Swipe, ⌘ + tab
Useful for Text Editing
Jump to Beginning/End of Line : ⌘ + Arrow Keys Jump to Beginning/End of Word : ⌃ + Arrow Keys Select Text : shift + Arrow Keys // Tip : shift + ⌘+ Arrow Keys , shift +⌃+ Arrow Keys Emoji & Special Character Input :⌃ +⌘ + space
Shell Commands
Open Finder from Shell : open .
Intellij Mac Command
Preferences : ⌘ + , Search All Files : ⌘ + shift + f Search Actions : ⌘ + shift + a Search Connected Server Task Name : ⌥ + shift + n
Navigate to Previous Cursor Position : ⌘ + [ Navigate to Next Cursor Position : ⌘ + ]
Move to Previous Tab : ⌘ + shift + [ Move to Next Tab : ⌘ + shift + ]
티스토리 이미지 업로드 오류 해결법 | How to Fix Tistory Image Upload Errors
쟈 미
728x90
티스토리 웹 에디터로 블로깅을 하다보면 ctrl+c ctrl+v를 이용해서 이미지를 업로드 해야하는 경우가 많습니다.
근데 이때 생기는 치명적인 오류가 있는데요.
구글링으로 얻은 이미지를 ctrl+c 해서 tistory에 ctrl+v를 할 때 간혹
붙여넣기 및 이미지 업로드 중입니다
이 글이 뜬 창 상태에서 멈추는 경우가 있어요ㅠㅠㅠ
이럴경우 새로 고침을 하면 그동안 쓴 글도 임시저장이 안되있는 상황이라서 날아가면 맘이 찢어집니다
이럴때 야매로 안에 있는 글이라도 복사할 수 있게 해결하는 방법을 포스팅 하려합니다.
이 상태에서 멈추었을 때 Ctrl + S 를 이용해서 HTML 파일로 저장합니다.
저장된 HTML 파일을 여는 동시에 Ctrl+A Ctrl+C 를 이용해서 전체 내용을 복사합니다. 이때 이 html 파일을 블러올 때 역시 일정 시간 (요청을 처리하는 시간)이 지나면 위에와 같은 "붙여넣기 및 이미지 업로드 중입니다" 창이 뜨게 되니 빠르게 Ctrl+A Ctrl+C를 해줍니다.
이후 복사한 내용을 새 Tistory 창을 열어서 복붙을 하면 내용만 가져올 수 있습니다 :)
긴 글을 쓰다가 저 창이 떠서 전부 날린적이 있는데 어떻게든 복구하고 싶어서 이것저것 해보다가 찾아낸 방법입니다ㅎㅎ 다들 꼭 임시저장을 활성화 하시길ㅠㅠ
+ 추가로 이 글을 해보면서 실험을 해보니 아이폰에서 카카오톡으로 이미지를 보냈는데 카카오톡에서 그 이미지를 바로 Ctrl+C 한 후 Tistory에서 Ctrl+V 하는 경우에 저런 "붙여넣기 및 이미지 업로드 중입니다" 이게 뜨는 것 같습니다!
아이폰에서 찍은 이미지는 확장자가 .HEIC인데, 이 파일을 그대로 Ctrl+C Ctrl+V하는 경우 에러가 뜨는 것으로 추측이 됩니다! (12/30 추가)
When you're blogging with the Tistory web editor, there are many cases where you need to upload images using ctrl+c ctrl+v.
But there's a critical bug that happens during this process.
When you ctrl+c an image you found on Google and ctrl+v it into Tistory, sometimes
Pasting and uploading image
It gets stuck on this popup and freezes 😭😭😭
If you refresh the page in this situation, everything you've written isn't auto-saved, so losing it all is absolutely heartbreaking.
So I'm going to share a workaround to at least copy the text that's still inside the editor.
When it's frozen in this state, use Ctrl + S to save the page as an HTML file.
Open the saved HTML file and immediately use Ctrl+A Ctrl+C to copy all the content. Note that when you open this HTML file, after a certain amount of time (the time it takes to process the request), the same "Pasting and uploading image" popup will appear again, so make sure to Ctrl+A Ctrl+C quickly.
Then open a new Tistory editor window and paste the copied content — you'll be able to recover just the text :)
I was writing a long post when that popup appeared and I lost everything — I was so desperate to recover it that I tried all sorts of things and discovered this method haha. Please make sure to enable auto-save, everyone 😭😭
+ Also, while experimenting with this, I found something: When you send an image from an iPhone via KakaoTalk and then directly Ctrl+C the image from KakaoTalk and Ctrl+V it into Tistory, that seems to be when the "Pasting and uploading image" popup appears!
Images taken on iPhones have a .HEIC extension, and I suspect the error occurs when you try to Ctrl+C Ctrl+V that file as-is! (Added 12/30)
test {
useJUnitPlatform()
}
dependencies {
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testCompile("org.assertj:assertj-core:3.11.1")
}
1. assertAll
User user = new User();
assertAll(
() -> asssertThat(user.getId()).isEqualTo(1L), //1
() -> asssertThat(user.getName()).isEqualTo("jyami"), //2
() -> asssertThat(user.getEmail()).isEqualTo("mor222293@gmail.com") //3
);
이전의 Junit4에서는 assertEquals을 검증할 때, 위에부터 하나씩 실행하는데, 위에서 실패하면 아래에있는 assertEquals를 실행하지 않는다.즉, 주석의 1번의 assertEquals에서 실패했으면 2, 3번의 assertEquals는 실행하지 않는다. 그러나 assertAll을 사용하면, 1번에서 실패했어도 2번 3번도 실행한다.
2. @DisplayName
@DisplayName("유저 테스트")
public class UserTest {
@DisplayName("유저의 이름을 테스트 해보자!")
@Test
void someTest() {
User user = new User();
assertThat(user.getName()).isEqualTo("jyami");
}
이렇게 할 경우에는, DisplayName을 이용해서 test의 목적을 명확히 명시할 수 있다.
contains는 순서와 상관 없이 실제 그룹이 주어진 값들을 포함하고 있는지를 테스트한다. 그래서 위 두 줄의 테스트는 모두 통과한다.
2. containsExactly()
@Test
void containsExactlyTest() {
List<Integer> integers = Arrays.asList(1, 2, 3);
assertThat(integers).containsExactly(1, 2, 3); //테스트 통과
assertThat(integers).containsExactly(2, 1, 3); //테스트 통과 X
assertThat(integers).containsExactly(1, 2); //테스트 통과 X
}
contains는 순서까지 고려해서 실제 그룹이 주어진 값들을 포함하고 있는지를 테스트한다 그래서 첫번째 줄의 테스트는 통과하지만, 두번째 줄의 테스트는 통과하지 못한다.
이때 주의할 점은 원소 하나라도 빠지면 테스트를 통과하지 못한다. 정말로 정확하게 일치하는 list여야 하는 것!
업데이트 예정인 게시글 입니다.
0. build.gradle
test {
useJUnitPlatform()
}
dependencies {
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testCompile("org.assertj:assertj-core:3.11.1")
}
1. assertAll
User user = new User();
assertAll(
() -> asssertThat(user.getId()).isEqualTo(1L), //1
() -> asssertThat(user.getName()).isEqualTo("jyami"), //2
() -> asssertThat(user.getEmail()).isEqualTo("mor222293@gmail.com") //3
);
In the previous JUnit4, when verifying with assertEquals, it executes them one by one from the top, and if one fails, it doesn't execute the ones below it. In other words, if assertEquals #1 in the comments fails, assertEquals #2 and #3 won't run. However, if you use assertAll, even if #1 fails, #2 and #3 still get executed.
2. @DisplayName
@DisplayName("유저 테스트")
public class UserTest {
@DisplayName("유저의 이름을 테스트 해보자!")
@Test
void someTest() {
User user = new User();
assertThat(user.getName()).isEqualTo("jyami");
}
By doing this, you can use DisplayName to clearly state the purpose of each test.
contains tests whether the actual group contains the given values regardless of order. So both lines of tests above will pass.
2. containsExactly()
@Test
void containsExactlyTest() {
List<Integer> integers = Arrays.asList(1, 2, 3);
assertThat(integers).containsExactly(1, 2, 3); //테스트 통과
assertThat(integers).containsExactly(2, 1, 3); //테스트 통과 X
assertThat(integers).containsExactly(1, 2); //테스트 통과 X
}
containsExactly tests whether the actual group contains the given values while also considering the order. So the first line's test passes, but the second line's test does not.
One thing to note here is that if even a single element is missing, the test will fail. The list really has to match exactly!
This is a post that will be updated in the future.
행사 자체는 Summit하고 굉장히 비슷했어요 GCP에 대한 전반적인 소개, 각 제품의 특징을 소개하는 세미나로 이루어 졌습니다.
그래도 중간에 quiklab 쿠폰이나 Coursera 쿠폰을 주셔서 줍줍 했네요ㅋㅋ
행사장 가는길 그리고 기념품
이번 행사는 끝나면 Cloud 팝소켓을 주더라구요! 수료증도 준다고 해서, 학교 빠진 것때문에 끝까지 앉아있다 왔습니다.
Google Cloud 행사에는 항상 게임기가 있네요ㅋㅋ
세션에 대한 정리는 위를 참고하시면 될 것 같구요.
사실 핸즈온 세션의 비중이 높은줄 알고왔지만 세션이 다 끝나고 있던 클라우드 히어로가 아무래도 직접 킥랩을 풀어보는 세션이라 그런지 가장 기억에 남네요
Google Cloud Platform 과 관련해서 문제를 푸는거였는데요 킥랩을 얼마나 많이 빨리 푸느냐에 따라 점수가 달라졌습니다. 아무래도 저는 GCP를 접한지 얼마 안되서 1번 2번을 풀다가 그만 했어요ㅋㅋ 3번은 kubernetes를 내 킥랩계정에 설정하는거였는데 kubernetes까지는 어렵더군요!
그래서 약 1시간동안 다같이 cloud hero문제를 풀고 1등부터 10등까지 랭킹에 드신분들에게는 히어로 망토랑 cloud 백팩을 주셨습니다!
근데 행사 당시 아무래도 인원이 많아서 그런지 인터넷도 너무 안좋았고, Gshell도 갑자기 너무 많은 요청이 들어와서 그런지 프로비저닝이 끝나지 않아서ㅠㅠㅠ 기다리던 시간이 조금 많았는데,
만약 제가 정말 GCP를 잘아는 사람이라서 망토를 노릴 정도였다면 많이 아쉬웠을 것 같아요.
3. 세미나 요약 표!
그래서 아무래도 전체 행사가 세미나로 이루어져 있다보니까 집에 돌아와서 세미나내용이라도 얼추 제대로 읽어보기라도 하자 생각해서 하게된게 블로그 포스팅이었습니다ㅋㅋ
온보딩에 못가서 어떤걸 했는지 아쉬웠던 분들은 참고 하시면 좋을 것 같아요
1. 컴퓨팅 옵션 비교
2. 부하 분산 옵션 비교
3. 상호 연결 옵션 비교
4. 스토리지 옵션 비교
5. Google Cloud Storage 클래스 중에서 선택하기
On November 26, 2019, I attended Google Cloud OnBoard held at Sejong University.
I had already been to the summit in early November, but I went again because they said there would be hands-on sessions.
To sum it up, contrary to my expectations, the seminar portion was longer than the hands-on sessions. Still, since I skipped school and invested a whole day to attend this event, I was thinking about how to make the most of the information I got — and that's how I ended up writing this blog post.
1. Handout Material — Word Transcription
I transferred the handout materials into a Word document to keep a mental note of what products are available. I figured it would come in handy as a reference when setting up infrastructure for backend development in the future. Here are the organized links:
The event itself was very similar to the Summit. It consisted of seminars that gave a general overview of GCP and introduced the features of each product.
But they did give out Qwiklabs coupons and Coursera coupons during the event, so I snagged those lol
On the way to the venue, and the swag
At this event, they gave out Cloud PopSockets when it was over! They also said they'd give out certificates of completion, so since I had already skipped school for this, I stayed until the very end.
There's always an arcade machine at Google Cloud events lol
You can refer to the links above for the session summaries.
I actually came expecting a heavy focus on hands-on sessions, but the Cloud Hero activity at the end — where you actually solve Qwiklabs challenges yourself — ended up being the most memorable part.
It was about solving problems related to Google Cloud Platform, and your score depended on how many Qwiklabs challenges you solved and how fast. Since I was pretty new to GCP, I only managed to solve problems 1 and 2 before calling it quits lol. Problem 3 was about setting up Kubernetes on your Qwiklabs account, and that was just too hard for me!
So after about an hour of everyone solving Cloud Hero challenges together, the top 10 ranked participants received hero capes and Cloud backpacks!
But since there were so many people at the event, the internet was really bad, and Google Cloud Shell seemed overwhelmed by all the requests — provisioning just wouldn't finish 😭😭😭 There was quite a bit of waiting around.
If I had actually been someone who knew GCP well enough to compete for the cape, I would've been pretty frustrated.
3. Seminar Summary Charts!
Since pretty much the entire event was seminars, I came home thinking I should at least properly read through the seminar content — and that's what led me to write this blog post lol
If you missed the onboarding event and were curious about what was covered, hopefully this will be helpful!
Cloud Dataproc: Managed Hadoop MapReduce, Spark, Pig, Hive service
Cloud Dataflow: Stream and batch processing, unified pipeline integration and simplification
BigQuery: Analytics database, data streaming at 100,000 rows per second
Cloud Pub/Sub: Scalable and flexible enterprise messaging
Cloud Datalab: Interactive data exploration
1-2. Cloud Dataproc
Features
Managed Hadoop
A fast and easy way to run GCP Hadoop and Spark/Hive/Pig as a managed service
Average cluster creation time under 90 seconds
Scale clusters up and down even while jobs are running
Why you should use it
Easily migrate on-premises Hadoop workloads to the cloud.
Quickly analyze data such as logs stored in Cloud Storage, create clusters in under 90 seconds on average, and delete them immediately.
Perform data mining and analysis quickly using Spark/Spark SQL.
Run classification algorithms using the Spark machine learning library (MLlib).
1-3. Cloud Dataflow
Features
Managed data pipelines
Processes data using Compute Engine instances
Automatic cluster size adjustment
Automated scaling, no instance provisioning required
Write code once for both batch and stream processing
Transform-based programming model
Data moves from sources through transformations in a Dataflow pipeline
Why you should use it
Move, filter, enrich, and shape data with ETL (Extract/Transform/Load) pipelines
Data analytics: Batch computation or continuous computation using streaming
Orchestration: Build pipelines that coordinate multiple services, including external services
Integrates with GCP services such as Cloud Storage, Cloud Pub/Sub, BigQuery, and Bigtable
Open source Java and Python SDKs
1-4. BigQuery
Fully managed data warehouse
Provides near real-time interactive analysis on massive datasets (hundreds of TB)
Queries using SQL syntax (SQL 2011)
No cluster maintenance required
Runs on Google's high-performance infrastructure
Compute and storage separated by a terabit-class network
Pay only for storage used and processing performed
Automatic discounts for long-term data storage
1-5. Cloud Pub/Sub
Features
Scalable and reliable messaging
Supports many-to-many asynchronous messaging: Create push/pull subscriptions to topics from application components
Includes offline consumer support
Leverages proven Google technology
Why you should use it
A building block for data ingestion in Dataflow, Internet of Things (IoT), and marketing analytics
Foundation for Dataflow streaming
Push notifications for cloud-based applications
Connect multiple applications within Google Cloud Platform (push/pull between Compute Engine and App Engine)
1-6. Cloud Datalab
Features
Provides interactive data exploration
An interactive tool for large-scale data exploration, transformation, analysis, and visualization
Integrated, open source: Built on Jupyter (IPython)
Why you should use it
Create and manage code, documentation, results, and visualizations in an intuitive notebook format Use Google Charts or matplotlib for easy visualization
Analyze data from BigQuery, Compute Engine, and Cloud Storage using Python, SQL, and JavaScript
Easily deploy models to BigQuery
2. Google Cloud AI Platform
2-1. Cloud AI Platform
An open source tool for building and running neural network models
Broad platform support: CPU or GPU, mobile, server, cloud
Fully managed machine learning service
Familiar notebook-based developer environment
Optimized for Google infrastructure, integrated with BigQuery and Cloud Storage
Pre-trained machine learning models built by Google
Speech: Streams results in real time and understands 80 languages
Vision: Identifies objects, landmarks, text, and content
Translation: Language detection and translation
Natural Language: Meaning and structure of text
Structured data: Classification and regression / Recommendations / Anomaly detection
Unstructured data: Image and video analysis / Text analysis
2-2. Cloud Vision API
Analyze images with a simple REST API
Logo detection, label recognition, and more
Features provided by Cloud Vision API
Extract useful information from images
Detect inappropriate content
Sentiment analysis
Text extraction
2-3. Cloud Speech API
Recognizes over 80 languages and variants
Can return text in real time
Provides high accuracy even in noisy environments
Accessible from any device
Powered by Google machine learning
2-4. Cloud Natural Language API
Uses machine learning models to understand the structure and meaning of text
Extracts information about topics mentioned in text documents, news articles, and blog posts.
Analyzes uploaded text on request or integrates with Cloud Storage.
2-5. Cloud Translation API
Translates arbitrary strings between numerous language pairs
Programmatically detects the language of a document
A service that provides the infrastructure level. The customer directly manages the OS and applications.
PaaS : Platform as a Service - heroku
A cloud service that provides developers with the capabilities needed to develop and serve applications. Users only manage applications and data.
2. Introduction to Containers
IaaS : Virtualizes hardware and allows resource sharing.
However, flexibility comes at the cost of boot time (minutes) and resources (GB).
App Engine
Provides access to programming services
A platform that rapidly scales apps independently based on workload and infrastructure as app demand grows
2-1. Containers
What containers provide
Offers the scalability of both IaaS and PaaS.
An abstraction layer over hardware and OS
An invisible box that provides configurable access to file systems, RAM, and networking divided into isolated partitions
Fast startup
Container capabilities
Configurable, independent, and highly portable.
Define your own hardware, OS, and software stack configuration
By treating the OS and hardware as a black box, there's no need to change or rebuild anything when migrating from development to staging to production, or from a laptop to the cloud.
A container is app + libraries: the OS/hardware implements the container interface
2-2. Clusters
Cluster capabilities
Allows deploying containers to server groups with a shared host configuration.
Connects multiple containers using network connections
Write modular code
Easy deployment
Achieve maximum efficiency and savings through independent scaling of containers and hosts
3. Kubernetes and Kubernetes Engine
3-1. Kubernetes
Easily orchestrates many containers across multiple hosts.
Build and run an app as a container
Docker : Bundles the app, dependencies, and system settings together
Other tools like Google Cloud Build can also be used. Code example: a Python Flask app that displays hello world
[app.py]
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "helloworld!"
if __name__ == "__main__":
app.run(host='0.0.0.0');
Bring the app to Kubernetes - Specify 4 things using a Docker file
The requirements.txt file for Flask dependencies
The OS image and version for Python
How to install Python
How to run the app
[requirement.txt]
Flask==0.12
uwsgi==2.0.15
FROM ubuntu:18.10
RUN apt-get update -y && \
apt-get install -y python3-pip python3-dev
COPY requirements.txt /app/requirements.txt
WORKDIR /app
RUN pip3 install -r requirements.txt
COPY ./app
ENDPOINT ["python3", "app.py"]
Build the container into an image and run it
Use docker build to build the container and save it as a locally runnable image
Upload images to a registry service (such as Google Container Registry) for sharing
Deploy containers to a collection of nodes called a cluster using the Kubernetes API
The master runs the control plane
Nodes run the containers
Nodes are VMs (used as GCE instances in GKE)
You describe the app, and Kubernetes figures out how to implement it
Bootstrapping Kubernetes Engine
In a GKE cluster, you can specify the following > Machine type > Number of nodes > Network settings, etc.
$> gcloud container clusters create k1
Use a wrapper called a Pod when deploying containers to nodes
Run a container in a Pod using Kubectl run
Kubectl is a command-line client for the Kubernetes API
This command starts a deployment with a container running in a Pod
In this case, the container is an image of an NGINX server
$> kubectl run nginx --image=nginx:1.15.7
Deployment
Manages a set of replica Pods for an app or workload, ensuring the desired number of Pods are running and remain healthy
$> kubectl get pods
Pods are only accessible within the cluster by default and have ephemeral IPs
Run Kubectl expose to attach a load balancer to the deployment so it's publicly accessible at a static IP
Kubernetes creates a service using the Pod's static IP, and the controller displays a message saying 'I need to attach an external load balancer with a public IP address'
Clients reaching this IP are routed to the Pods behind the service
For example, if you create two sets of Pods named frontend and backend and place them behind their own services, changes in the backend Pods won't be noticed by the frontend Pods. They simply reference the backend service.
Run kubectl get services to get the public IP of the service
$> kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx LoadBalancer 10.0.65.118 104.198.149.140 80/TCP 5m
Run kubectl scale to scale the deployment
$> kubectl scale nginx ==replicas=3
Use various parameters to enable autoscaling, or place autoscaling behind programming logic for intelligent management
Run kubectl apply -f to declaratively apply changes
$> kubectl apply -f nginx-deployment.yaml
Run kubectl get replicasets to check the update status
$> kubectl get replicasets
NAME DESIRED CURRENT READY AGE
nginx-2035384211 5 3 3 2s
Run kubectl get pods to verify the Pods are coming online
$> kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-203584211-7ci7o 1/1 Running 0 18s
nginx-203584211-he3h3 1/1 Running 0 18s
nginx-203584211-qqcnn 1/1 Running 0 18s
nginx-203584211-abbcc 1/1 Running 0 18s
nginx-203584211-knlen 1/1 Running 0 18s
Run kubectl get deployments to describe the deployment and verify the correct number of replicas are running
$> kubectl get deployments
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
nginx 5 5 5 5 18s
Build the container and run the image
$> kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx LoadBalancer 10.0.65.118 104.198.149.140 80/TCP 5m
4. Google App Engine
A PaaS for building scalable applications
App Engine makes deployment, maintenance, and scaling easy, so you can focus solely on innovation
Particularly well-suited for building scalable web applications and mobile backends
5. Google App Engine Standard Environment
Easy application deployment
Automatic workload scaling in response to demand
Cost-effective
Free daily quota / usage-based pricing
SDKs for development, testing, and deployment
Supports specific versions of Java, Python, PHP, and Go
Applications must comply with sandbox constraints
No writing to the local file system
A 60-second timeout applies to all requests
Third-party software installation is restricted
Example web application
6. Google App Engine Flexible Environment
Build and deploy containerized apps with a single click
No sandbox constraints
Access to App Engine resources
Standard runtimes: Python, Java, Go, Node.js
Custom runtime support: Any language that supports HTTP requests
Package the runtime as a Dockerfile
App Engine Environment Comparison
7. Google Cloud Endpoints and Apigee Edge
Application programming interfaces hide implementation details and enforce contracts [diagram]
7-1. Cloud Endpoints
Supports API creation and maintenance
Distributed API management through the API console
Expose APIs using RESTful interfaces
Access control and call validation using JSON Web Tokens and Google API keys -> Verify web and mobile user identity through Auth0 and Firebase Authentication
Client library generation
Supported platforms [diagram]
7-2. Apigee Edge
Supports API security and monetization
A platform where customers and partners can use APIs
Provides analytics, monetization, and developer portal
8. Development, Deployment, and Monitoring in the Cloud
8-1. Cloud Source Repositories
Fully-featured Git repositories hosted on Google Cloud Platform
Supports collaborative development of cloud apps
Provides integration with Stackdriver Debugger
8-2. Cloud Functions
Create single-purpose functions that respond to events without a server or runtime Event examples: A new instance is created. A file is added to Cloud Storage.
Written in Javascript, runs in a managed Node.js environment on Google Cloud Platform
8-3. Deployment Manager
Infrastructure management service
Create .yaml templates that describe your environment and use Deployment Manager to create resources
댓글
Comments