1.Apex jobs에서는 모든 비동기 Apex 작업이 표시되며
jobId를 사용해 아래와 같이 쿼리로 조회할 수도 있다.
AsyncApexJob jobInfo = [SELECT Status, NumberOfErrors
FROM AsyncApexJob WHERE Id = :jobID];
2.(Quick Start: Lightning Web Components)
Trailhead Playground 사용자 이름 및 비밀번호 받기는 playground에서 아래와 같은 절차로 진행된다.
- Login Credentials을 playground에서 받아둔다.
- 탭을 클릭 하고 사용자 이름을 기록
- 내 비밀번호 재설정을 클릭
- 이메일에 전송된 링크를 클릭
- 비밀번호 변경을 클릭 후 새 비밀번호를 입력
또한 sfdx update를 CLI 부분에 입력해 최신 버전인지를 확인해야 한다.
3.Quick Start: Lightning Web Components 부분 선행 요청으로 트레일을 수행하던 중
SFDX: Authorize an Org를 선택할 수 없는 문제가 발생했다.
예전에도 비슷한 경험이 있었던 것 같은데 검색을 해보니
생성을 한 직후에 이렇게 잡히지 않는 경우가 있는데
open→folder로 folder를 인식시켜주면 다시 SFDX: Authorize an Org를 선택할 수 있다.
4.Lightning web component에는 폴더 이름과 네임스페이스가 존재하는데
폴더 이름의 공백은 IDE 내부에서는 허용하지 않기 때문에 카멜케이스(’aaBb’)로 작성하고
태그에서 참조하려면 공백은 하이폰(’-’)으로 치환되기 때문에 <aa-bb>로 사용하게 된다.
5.Lightning Web Components Basics과정을 따라가다 보면 자전거 띄우기가 나오는데
실제 lightning app builder에 들어가면 나오지 않는 것을 볼 수 있다.
이건 기본 생성에는 target이 잡혀있지 않기 때문인데
아래와 같은 target 추가를 통해 app builder에서도 작성한 페이지를 사용할 수 있다.
또한 isExposed가 false로 default 잡혀있는데
이런 경우 Lightning 앱 빌더 또는 익스피리언스 빌더에 노출되지 않기 떄문에
true 및 target 설정을 해야 한다.
(true를 하고 target 설정을 하는 과정인 것 같다)
//html
<template>
<div>
<div>Name: {name}</div>
<div>Description: {description}</div>
<div>Category: {category}</div>
<div>Material: {material}</div>
<div>Price: {price}</div>
<div><img src={pictureUrl}/></div>
</div>
</template>
//js
import { LightningElement } from 'lwc';
export default class App extends LightningElement {
name = 'Electra X4';
description = 'A sweet bike built for comfort.';
category = 'Mountain';
material = 'Steel';
price = '$2,700';
pictureUrl = 'https://s3-us-west-1.amazonaws.com/sfdc-demo/ebikes/electrax4.jpg';
}
//meta
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>56.0</apiVersion>
<isExposed>true</isExposed>
<targets>
<target>lightning__AppPage</target>
<target>lightning__RecordPage</target>
<target>lightning__HomePage</target>
</targets>
</LightningComponentBundle>
정확히는 isExposed를 true로 할 경우 구성 요소를 다른 네임스페이스에서 사용할 수 있도록 하며
true 또는 false의 값을 필수적으로 기입해야 한다.
하지만 targets 부분은 선택적 요소로 앱 빌더에서 구성 요소를 추가할 수 있는 유형을 지정한다.
6.아래와 같은 data, detail, list, selector, tile 코드를 작성해
페이지를 구성할 수 있다.
//selector html
<template>
<div class="wrapper">
<header class="header">Available Bikes for {name}</header>
<section class="content">
<div class="columns">
<main class="main" >
<c-list onproductselected={handleProductSelected}></c-list>
</main>
<aside class="sidebar-second">
<c-detail product-id={selectedProductId}></c-detail>
</aside>
</div>
</section>
</div>
</template>
//selector js
import { LightningElement, wire } from 'lwc';
import { getRecord, getFieldValue } from 'lightning/uiRecordApi';
import Id from '@salesforce/user/Id';
import NAME_FIELD from '@salesforce/schema/User.Name';
const fields = [NAME_FIELD];
export default class Selector extends LightningElement {
selectedProductId;
handleProductSelected(evt) {
this.selectedProductId = evt.detail;
}
userId = Id;
@wire(getRecord, { recordId: '$userId', fields })
user;
get name() {
return getFieldValue(this.user.data, NAME_FIELD);
}
}
//selector css
body {
margin: 0;
}
.wrapper{
min-height: 100vh;
background: #ccc;
display: flex;
flex-direction: column;
}
.header, .footer{
height: 50px;
background: rgb(255, 255, 255);
color: rgb(46, 46, 46);
font-size: x-large;
padding: 10px;
}
.content {
display: flex;
flex: 1;
background: #999;
color: #000;
}
.columns{
display: flex;
flex:1;
}
.main{
flex: 1;
order: 2;
background: #eee;
}
.sidebar-first{
width: 20%;
background: #ccc;
order: 1;
}
.sidebar-second{
width: 30%;
order: 3;
background: #ddd;
}
//selector meta
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>48.0</apiVersion>
<isExposed>true</isExposed>
<targets>
<target>lightning__AppPage</target>
<target>lightning__RecordPage</target>
<target>lightning__HomePage</target>
</targets>
</LightningComponentBundle>
//------------------------------------------------------------------
//data.js
export const bikes = [
{"apiName":"Product__c","childRelationships":{},"fields":{"Category__c":{"displayValue":"Mountain","value":"Mountain"},"CreatedDate":{"displayValue":null,"value":"2018-10-09T03:29:52.000Z"},"Description__c":{"displayValue":null,"value":"A durable e-bike with great looks."},"Id":{"displayValue":null,"value":"a0256000001F1arAAC"},"LastModifiedDate":{"displayValue":null,"value":"2018-10-12T02:57:48.000Z"},"Level__c":{"displayValue":"Racer","value":"Racer"},"MSRP__c":{"displayValue":"$7,800","value":7800},"Material__c":{"displayValue":"Carbon","value":"Carbon"},"Name":{"displayValue":null,"value":"DYNAMO X1"},"Picture_URL__c":{"displayValue":null,"value":"https://s3-us-west-1.amazonaws.com/sfdc-demo/ebikes/dynamox1.jpg"},"SystemModstamp":{"displayValue":null,"value":"2018-10-12T02:57:48.000Z"}},"id":"a0256000001F1arAAC","lastModifiedById":null,"lastModifiedDate":"2018-10-12T02:57:48.000Z","recordTypeInfo":null,"systemModstamp":"2018-10-12T02:57:48.000Z"},
{"apiName":"Product__c","childRelationships":{},"fields":{"Category__c":{"displayValue":"Mountain","value":"Mountain"},"CreatedDate":{"displayValue":null,"value":"2018-10-09T03:29:52.000Z"},"Description__c":{"displayValue":null,"value":"A durable e-bike with great looks."},"Id":{"displayValue":null,"value":"a0256000001F1atAAC"},"LastModifiedDate":{"displayValue":null,"value":"2018-10-10T17:26:47.000Z"},"Level__c":{"displayValue":"Racer","value":"Racer"},"MSRP__c":{"displayValue":"$6,802","value":6802},"Material__c":{"displayValue":"Aluminum","value":"Aluminum"},"Name":{"displayValue":null,"value":"DYNAMO X2"},"Picture_URL__c":{"displayValue":null,"value":"https://s3-us-west-1.amazonaws.com/sfdc-demo/ebikes/dynamox2.jpg"},"SystemModstamp":{"displayValue":null,"value":"2018-10-10T17:26:47.000Z"}},"id":"a0256000001F1atAAC","lastModifiedById":null,"lastModifiedDate":"2018-10-10T17:26:47.000Z","recordTypeInfo":null,"systemModstamp":"2018-10-10T17:26:47.000Z"},
{"apiName":"Product__c","childRelationships":{},"fields":{"Category__c":{"displayValue":"Mountain","value":"Mountain"},"CreatedDate":{"displayValue":null,"value":"2018-10-09T03:29:52.000Z"},"Description__c":{"displayValue":null,"value":"A durable e-bike with great looks."},"Id":{"displayValue":null,"value":"a0256000001F1auAAC"},"LastModifiedDate":{"displayValue":null,"value":"2018-10-09T04:37:56.000Z"},"Level__c":{"displayValue":"Enthusiast","value":"Enthusiast"},"MSRP__c":{"displayValue":"$5,601","value":5601},"Material__c":{"displayValue":"Aluminum","value":"Aluminum"},"Name":{"displayValue":null,"value":"DYNAMO X3"},"Picture_URL__c":{"displayValue":null,"value":"https://s3-us-west-1.amazonaws.com/sfdc-demo/ebikes/dynamox3.jpg"},"SystemModstamp":{"displayValue":null,"value":"2018-10-09T04:37:56.000Z"}},"id":"a0256000001F1auAAC","lastModifiedById":null,"lastModifiedDate":"2018-10-09T04:37:56.000Z","recordTypeInfo":null,"systemModstamp":"2018-10-09T04:37:56.000Z"},
{"apiName":"Product__c","childRelationships":{},"fields":{"Category__c":{"displayValue":"Mountain","value":"Mountain"},"CreatedDate":{"displayValue":null,"value":"2018-10-09T03:29:52.000Z"},"Description__c":{"displayValue":null,"value":"A durable e-bike with great looks."},"Id":{"displayValue":null,"value":"a0256000001F1avAAC"},"LastModifiedDate":{"displayValue":null,"value":"2018-10-09T03:29:52.000Z"},"Level__c":{"displayValue":"Enthusiast","value":"Enthusiast"},"MSRP__c":{"displayValue":"$5,500","value":5500},"Material__c":{"displayValue":"Aluminum","value":"Aluminum"},"Name":{"displayValue":null,"value":"DYNAMO X4"},"Picture_URL__c":{"displayValue":null,"value":"https://s3-us-west-1.amazonaws.com/sfdc-demo/ebikes/dynamox4.jpg"},"SystemModstamp":{"displayValue":null,"value":"2018-10-09T03:29:52.000Z"}},"id":"a0256000001F1avAAC","lastModifiedById":null,"lastModifiedDate":"2018-10-09T03:29:52.000Z","recordTypeInfo":null,"systemModstamp":"2018-10-09T03:29:52.000Z"},
{"apiName":"Product__c","childRelationships":{},"fields":{"Category__c":{"displayValue":"Mountain","value":"Mountain"},"CreatedDate":{"displayValue":null,"value":"2018-10-09T03:29:52.000Z"},"Description__c":{"displayValue":null,"value":"A durable e-bike with great looks."},"Id":{"displayValue":null,"value":"a0256000001F1azAAC"},"LastModifiedDate":{"displayValue":null,"value":"2018-10-09T03:29:52.000Z"},"Level__c":{"displayValue":"Enthusiast","value":"Enthusiast"},"MSRP__c":{"displayValue":"$4,600","value":4600},"Material__c":{"displayValue":"Aluminum","value":"Aluminum"},"Name":{"displayValue":null,"value":"FUSE X1"},"Picture_URL__c":{"displayValue":null,"value":"https://s3-us-west-1.amazonaws.com/sfdc-demo/ebikes/fusex1.jpg"},"SystemModstamp":{"displayValue":null,"value":"2018-10-09T03:29:52.000Z"}},"id":"a0256000001F1azAAC","lastModifiedById":null,"lastModifiedDate":"2018-10-09T03:29:52.000Z","recordTypeInfo":null,"systemModstamp":"2018-10-09T03:29:52.000Z"},
{"apiName":"Product__c","childRelationships":{},"fields":{"Category__c":{"displayValue":"Commuter","value":"Commuter"},"CreatedDate":{"displayValue":null,"value":"2018-10-09T03:29:52.000Z"},"Description__c":{"displayValue":null,"value":"A durable e-bike with great looks."},"Id":{"displayValue":null,"value":"a0256000001F1b2AAC"},"LastModifiedDate":{"displayValue":null,"value":"2018-10-09T04:41:56.000Z"},"Level__c":{"displayValue":"Beginner","value":"Beginner"},"MSRP__c":{"displayValue":"$3,200","value":3200},"Material__c":{"displayValue":"Aluminum","value":"Aluminum"},"Name":{"displayValue":null,"value":"ELECTRA X1"},"Picture_URL__c":{"displayValue":null,"value":"https://s3-us-west-1.amazonaws.com/sfdc-demo/ebikes/electrax1.jpg"},"SystemModstamp":{"displayValue":null,"value":"2018-10-09T04:41:56.000Z"}},"id":"a0256000001F1b2AAC","lastModifiedById":null,"lastModifiedDate":"2018-10-09T04:41:56.000Z","recordTypeInfo":null,"systemModstamp":"2018-10-09T04:41:56.000Z"},
{"apiName":"Product__c","childRelationships":{},"fields":{"Category__c":{"displayValue":"Commuter","value":"Commuter"},"CreatedDate":{"displayValue":null,"value":"2018-10-09T03:29:52.000Z"},"Description__c":{"displayValue":null,"value":"A durable e-bike with great looks."},"Id":{"displayValue":null,"value":"a0256000001F1b3AAC"},"LastModifiedDate":{"displayValue":null,"value":"2018-10-09T03:29:52.000Z"},"Level__c":{"displayValue":"Beginner","value":"Beginner"},"MSRP__c":{"displayValue":"$3,200","value":3200},"Material__c":{"displayValue":"Aluminum","value":"Aluminum"},"Name":{"displayValue":null,"value":"ELECTRA X2"},"Picture_URL__c":{"displayValue":null,"value":"https://s3-us-west-1.amazonaws.com/sfdc-demo/ebikes/electrax2.jpg"},"SystemModstamp":{"displayValue":null,"value":"2018-10-09T03:29:52.000Z"}},"id":"a0256000001F1b3AAC","lastModifiedById":null,"lastModifiedDate":"2018-10-09T03:29:52.000Z","recordTypeInfo":null,"systemModstamp":"2018-10-09T03:29:52.000Z"},
{"apiName":"Product__c","childRelationships":{},"fields":{"Category__c":{"displayValue":"Commuter","value":"Commuter"},"CreatedDate":{"displayValue":null,"value":"2018-10-09T03:29:52.000Z"},"Description__c":{"displayValue":null,"value":"A durable e-bike with great looks."},"Id":{"displayValue":null,"value":"a0256000001F1b6AAC"},"LastModifiedDate":{"displayValue":null,"value":"2018-10-09T03:29:52.000Z"},"Level__c":{"displayValue":"Beginner","value":"Beginner"},"MSRP__c":{"displayValue":"$2,700","value":2700},"Material__c":{"displayValue":"Aluminum","value":"Aluminum"},"Name":{"displayValue":null,"value":"ELECTRA X3"},"Picture_URL__c":{"displayValue":null,"value":"https://s3-us-west-1.amazonaws.com/sfdc-demo/ebikes/electrax3.jpg"},"SystemModstamp":{"displayValue":null,"value":"2018-10-09T03:29:52.000Z"}},"id":"a0256000001F1b6AAC","lastModifiedById":null,"lastModifiedDate":"2018-10-09T03:29:52.000Z","recordTypeInfo":null,"systemModstamp":"2018-10-09T03:29:52.000Z"},
{"apiName":"Product__c","childRelationships":{},"fields":{"Category__c":{"displayValue":"Commuter","value":"Commuter"},"CreatedDate":{"displayValue":null,"value":"2018-10-09T03:29:52.000Z"},"Description__c":{"displayValue":null,"value":"A durable e-bike with great looks."},"Id":{"displayValue":null,"value":"a0256000001F1b7AAC"},"LastModifiedDate":{"displayValue":null,"value":"2018-10-09T03:29:52.000Z"},"Level__c":{"displayValue":"Beginner","value":"Beginner"},"MSRP__c":{"displayValue":"$2,700","value":2700},"Material__c":{"displayValue":"Aluminum","value":"Aluminum"},"Name":{"displayValue":null,"value":"ELECTRA X4"},"Picture_URL__c":{"displayValue":null,"value":"https://s3-us-west-1.amazonaws.com/sfdc-demo/ebikes/electrax4.jpg"},"SystemModstamp":{"displayValue":null,"value":"2018-10-09T03:29:52.000Z"}},"id":"a0256000001F1b7AAC","lastModifiedById":null,"lastModifiedDate":"2018-10-09T03:29:52.000Z","recordTypeInfo":null,"systemModstamp":"2018-10-09T03:29:52.000Z"}
];
//data.meta
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>48.0</apiVersion>
<isExposed>false</isExposed>
</LightningComponentBundle>
//------------------------------------------------------------------
//detail.html
<template>
<template if:true={product}>
<div class="container">
<div class="slds-text-heading_small">{product.fields.Name.value}</div>
<div class="price">{product.fields.MSRP__c.displayValue}</div>
<div class="description">{product.fields.Description__c.value}</div>
<img class="product-img" src={product.fields.Picture_URL__c.value}></img>
<p>
<lightning-badge label={product.fields.Material__c.value}></lightning-badge>
<lightning-badge label={product.fields.Level__c.value}></lightning-badge>
</p>
<p>
<lightning-badge label={product.fields.Category__c.value}></lightning-badge>
</p>
</div>
</template>
<template if:false={product}>
<div class="slds-text-heading_medium">Select a bike</div>
</template>
</template>
//detail.js
import { LightningElement, api } from 'lwc';
import { bikes } from 'c/data';
export default class Detail extends LightningElement {
// Ensure changes are reactive when product is updated
product;
// Private var to track @api productId
_productId = undefined;
// Use set and get to process the value every time it's
// requested while switching between products
set productId(value) {
this._productId = value;
this.product = bikes.find(bike => bike.fields.Id.value === value);
}
// getter for productId
@api get productId(){
return this._productId;
}
}
//detail.css
ebody{
margin: 0;
}
.price {
color: green;
font-weight: bold;
}
//detail.meta
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>48.0</apiVersion>
<isExposed>false</isExposed>
</LightningComponentBundle>
//------------------------------------------------------------------
//list.html
<template>
<div class="container">
<template for:each={bikes} for:item="bike">
<c-tile
key={bike.fields.Id.value}
product={bike}
ontileclick={handleTileClick}>
</c-tile>
</template>
</div>
</template>
//list.js
import { LightningElement } from 'lwc';
import { bikes } from 'c/data';
export default class List extends LightningElement {
bikes = bikes;
handleTileClick(evt) {
// This component wants to emit a productselected event to its parent
const event = new CustomEvent('productselected', {
detail: evt.detail
});
// Fire the event from c-list
this.dispatchEvent(event);
}
}
//list.css
.container {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
//list.meta
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>48.0</apiVersion>
<isExposed>false</isExposed>
</LightningComponentBundle>
//------------------------------------------------------------------
//tile.html
<template>
<div class="container">
<a onclick={tileClick}>
<div class="title">{product.fields.Name.value}</div>
<img class="product-img" src={product.fields.Picture_URL__c.value}></img>
</a>
</div>
</template>
//tile.js
import { LightningElement, api } from 'lwc';
export default class Tile extends LightningElement {
@api product;
tileClick() {
const event = new CustomEvent('tileclick', {
// detail contains only primitives
detail: this.product.fields.Id.value
});
// Fire the event from c-tile
this.dispatchEvent(event);
}
}
//tile.css
.container {
border: 1px rgb(168, 166, 166) solid;
border-radius: 5px;
background-color: white;
margin:5px;
padding: 2px;
max-width: 110px;
display: flex;
}
.title {
font-weight: strong;
}
.product-img {
max-width: 100px;
}
a {
text-decoration: none;
}
a:link {
color: rgb(159, 159, 159);
}
a:visited {
color: green;
}
a:hover {
color: hotpink;
}
a:active {
color: blue;
}
//tile.meta
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>48.0</apiVersion>
<isExposed>false</isExposed>
</LightningComponentBundle>
7.쿼리문을 요청할 경우 시스템적으로 전송하기 떄문에 권한을 무시한다.
보안을 적용해 접근할 데이터의 여부를 결정하기 위해서는
아래의 코드처럼 작동 전 권한을 확인하고 쿼리를 실행하는 방식으로 진행할 수 있다.
// update
if (Schema.sObjectType.Contact.fields.Email.isUpdateable()) {
// Update contact email address
}
//create
if (Schema.sObjectType.Contact.fields.Email.isCreateable()) {
// Create new contact
}
//read
if (Schema.sObjectType.Contact.fields.Email.isAccessible()) {
Contact c = [SELECT Email FROM Contact WHERE Id= :Id];
}
//delete
if (Schema.sObjectType.Contact.isDeletable()) {
// Delete contact
}
8.SOQL은 SQL에서 파생된 salesforce용 SQL이기 때문에 SQL과의 차이점들이 존재한다.
- INSERT, UPDATE, DELETE가 없으며 SELECT만 존재
- 명령 실행 불가
- JOIN
- UNION 연산자
- 쿼리 체인
9.SOQL Injection을 막기 위해 아래와 같은 방법들이 존재한다.
- Static queries with bind variables - 정적 쿼리 사용을 통해 특정 위치에만 값을 변수로 할당
- String.escapeSingleQuotes() - 작은 따음표를 없애 쿼리로 인식하지 못하게 하는 방식
- Type casting - 형변환을 통해 예측과 다른 타입이 입력될 경우 에러를 반환하는 방법
- Replacing characters - 공백을 제거하는 등 하나의 입력값으로 인식하게 만드는 방법
- Allowlisting - 허용 목록을 만들어 해당 입력값이 아니면 차단하는 방식
10.CSRF란 특정 주소값을 통해 명령을 내리는 사이트의 경우
권한을 가진 유저를 리다이렉트를 통해 본인이 원하는 명령을 내리는 주소값으로 보내는 방식이다.
이를 막기 위해서 주소 접속만으로 요청을 보내지 못하게 하거나
고유한 토큰으로 정확한 값을 추측하지 못하게 하는 등의 방지법이 있다.
11.개발자 콘솔에서는 작업 공간 설정을 할 수 있는데
작업 공간은 다른 프로젝트나 다른 팀원과 겹치지 않도록 별도로 구분하는 공간이라고 볼 수 있다.
WorkSpace → New Workspace에서 새 작업 공간을 생성하고
WorkSpace → Switch Workspace에서 작업 공간을 이동할 수 있다.
12.디버그에서 특정 명령을 내린 경우 로그가 생성되는데
해당 로그는 Timestamp, Event, Details로 구분된다.
각각은 작동 시간, 이벤트 종류, 세부 사항이 출력되며
Open Raw Log를 클릭할 경우 나노초 단위까지 시간을 체크할 수 있게 된다.
details의 정보로는 부족하다고 생각될 경우
직접 코드 사이에 System.debug()를 사용해 조회하고 싶은 값들을 출력해볼 수 있으며
체크포인트를 사용해 해당 상태에서의 전체적인 데이터를 조회할 수도 있다.
일반적으로 출력되는 로그는 8가지 단계로 구분되는데
로그 출력 없음인 NONE부터 최대 많은 정보 수준인 FINEST까지 존재한다.
(NONE < ERROR < WARN < INFO < DEBUG < FINE < FINER < FINEST)
13.설계 단계에서 감지되지 않은 버그는 코딩 단계에서 10배의 시간을 소모하게 만들고
디버깅 단계에서 10배 더 많은 시간을 소모하게 만든다는 말처럼 디버깅은 쉽지 않다.
하지만 Apex Replay Debugger를 사용할 경우 체크포인트를 사용해 어디서 문제가 발생했는지 알 수 있고
SFDX: Turn On Apex Debug Log for Replay Debugger를 사용해 로그를 확인할 수 있다.
(1).백준 11024번 더하기 4는 다른 더하기 문제와 유사하게
입력된 숫자를 더하는 것은 같았지만 각 줄마다의 합을 출력해야 했고
최상단에 테스트케이스의 갯수가 출력됐다.
const input = `2
1 2 3 4 5
5 4 5 4 2 3 1 2`.split('\n')
const result = []
for(let i = 1 ; i < input.length ; i++){
const arr = input[i].split(' ').map(Number)
let sum = 0
for(let j = 0 ; j < arr.length ; j++){
sum += arr[j]
}
result.push(sum)
}
console.log(result.join('\n'))