on
Webix 스프레드시트. 엑셀의 본격적인 웹 대안인가요?
Webix 스프레드시트. 엑셀의 본격적인 웹 대안인가요?
데스크톱 소프트웨어에서 유사한 온라인 서비스로 점진적으로 전환하는 주제를 계속하면서, 본 출판물에서는 "Excel"과 경쟁할 수 있는 스프레드시트 위젯에 대해 말씀드리고자 합니다. 모든 스프레드쉬트를 완벽하게 지원하는 탁월한 자바스크립트 구성 요소입니다. 한편, 이 툴은 매우 유연하며 모든 환경에 쉽게 통합될 수 있습니다.
비즈니스 애플리케이션에 광범위한 기능과 고성능의 Excel과 유사한 도구를 추가해야 하는 경우 Webix 팀이 제공하는 스프레드시트 위젯에 주목해야 합니다. 그들이 우리에게 무엇을 제공할 수 있는지, 그리고 그 게임이 이길 가치가 있는지 알아보자.
JS 스프레드시트란?
Webix 스프레드쉬트는 다양한 복잡성의 스프레드시트로 작업할 수 있는 포괄적인 자바스크립트 솔루션입니다. 구성요소는 웨빅스 라이브러리의 복잡한 위젯 라인에서 가장 고급화된 도구 중 하나입니다.
최근(버전 8.2부터) 스프레드쉬트는 새로운 엔진과 멀티시트 수학 지원을 받았습니다. 이러한 업데이트는 이전 버전에 비해 성능이 크게 향상되었습니다.
위젯 기능
도구 기능은 상당히 광범위합니다. 스프레드시트를 만들고, 사용하기 쉬운 인터페이스를 통해 데이터를 관리하며, 필요한 형식(Excel, PDF, CSV 또는 PNG)으로 데이터를 내보낼 수 있습니다. 직접 시트를 작성할 뿐만 아니라, Excel 형식의 로컬 데이터를 가져와 필요에 따라 변경할 수 있습니다.
특히 다음과 같은 방법으로 테이블을 사용할 수 있습니다.
시트 작성, 복사 및 삭제
시트 수출, 수입 및 인쇄
변화 역사를 관리하다
셀 내용물을 스타일링하다
셀 내용 정렬, 필터링 및 차단
링크, 사진, 차트 및 주석을 셀 및 위에 추가
열 및 행 관리:
덧셈과 뺄셈
숨어서 드러내다
크기 조정과 동결하다
덧셈과 뺄셈 숨어서 드러내다 크기 조정과 동결하다 덧셈과 뺄셈
숨어서 드러내다
크기 조정과 동결하다
다양한 공식 등을 적용하다
보시다시피 위젯의 기능은 충분히 크고 기능은 데스크톱 기능보다 뒤지지 않습니다. 스프레드시트 기능에 대한 자세한 내용은 관련 문서를 참조하십시오.
위젯 인터페이스
편리하고 사용자 친화적인 인터페이스를 통해 위젯으로 작업할 수 있습니다. 엑셀 경험이 있는 사용자라면 구성 요소 UI를 이해하는 데 어려움이 없습니다. 시각적으로 다음과 같은 세 부분으로 구성됩니다.
도구 모음
작업 공간
맨 아래 막대.
도구 모음에는 기능 그룹으로 구분된 서로 다른 컨트롤이 포함되어 있습니다. 이들의 도움을 받아 시트 데이터를 관리할 수 있습니다. 위젯 설정에 따라 컨트롤이 다를 수 있습니다. 나중에 얘기하죠.
구성 요소의 작업 공간에서 작업할 스프레드시트를 살펴볼 수 있습니다. 도구 모음 컨트롤을 사용하여 테이블 데이터를 관리하고 직접 변경할 수 있습니다.
또한 응용 프로그램 하단에는 시트 사이를 탐색할 수 있는 하단 막대가 있으며 시트 추가, 삭제 및 이름을 변경할 수 있습니다.
이제 위젯 기능과 인터페이스에 대해 간략하게 설명한 후 기본 구성으로 위젯을 실제로 만드는 방법에 대해 살펴보겠습니다.
기본 기능으로 위젯을 만드는 방법
Webix 스프레드시트(Webix 스프레드시트)는 Webix 라이브러리의 가장 고급 도구 중 하나입니다. 위젯은 라이브러리의 Pro 버전으로 배포되지만 위젯에는 포함되지 않습니다. 이 구성 요소는 라이센스 패키지의 일부로 구입할 수 있습니다. 라이센싱 페이지에서 자세히 알아보십시오.
스프레드쉬트로 작업할 때의 모든 이점과 유연성을 확인하려면 라이브러리의 평가판 Pro 버전을 다운로드하십시오. 모든 복잡한 위젯을 포함하며 30일 동안 무료로 사용할 수 있습니다.
이제 페이지에 위젯을 포함시키고 기본 기능으로 실행하는 방법을 알아보겠습니다. 그리고 이것은 명확하고 간단한 방법으로 이루어집니다. 스프레드쉬트가 Webix 구성 요소를 기반으로 한다는 점을 고려하여 먼저 라이브러리 원본을 포함해야 합니다. 그런 다음 위젯 자체의 .js 및 .css 파일에 대한 링크를 지정해야 합니다. 코드에서는 다음과 같습니다.
필요한 소스를 포함하면 몇 줄의 코드로 위젯을 초기화할 수 있습니다. 이렇게 하려면 webix.ui() 생성자를 호출하여 필요한 구성의 개체를 전달해야 합니다.
HTML 페이지가 완전히 로드된 후 응용 프로그램 코드 실행을 시작하려면 webix.ready(함수){ /* 생성자 */ } 메서드에 생성자를 넣습니다. 코드에는 다음과 같이 표시됩니다.
webix.ready(function(){ webix.ui({ view: "spreadsheet", url: "some_data_link" }); });
이제 스프레드시트 위젯의 기본 기능을 사용할 수 있습니다. 구성 요소 기능을 사용자 정의할 수 있는 기능이 있다는 점을 여기서 언급할 필요가 있습니다. 예를 들어 필요한 도구를 추가하거나 불필요한 도구를 제거할 수 있습니다. 브라우저에서 다음 결과를 볼 수 있습니다.
스프레드시트 구성 방법
스프레드시트 위젯은 생성자의 한 종류입니다. 그것의 특징은 그것이 많은 개별적인 웨빅스 구성 요소들로 구성되어 있다는 사실에 있다. 각각의 속성 및 방법이 있습니다. 이러한 API를 사용하여 인터페이스와 인터페이스의 동작(예: 도구 모음의 컨트롤)의 하나 또는 다른 요소를 사용자 정의할 수 있습니다.
또한 구성 요소 자체에는 구성 요소를 사용자 정의하고 동작을 관리할 수 있는 고유한 속성 및 메서드의 풍부한 집합이 있습니다. 또한 Webix 위젯을 구성하기 위해 선언적 접근 방식을 사용해야 한다는 점을 분명히 할 필요가 있습니다. 이는 모든 매개 변수가 가장 편리한 JSON 구문을 사용하여 지정됨을 의미합니다. 필요한 속성을 해당 값으로 설정하기만 하면 됩니다.
위젯 자체는 "스프레드시트" 식 보기를 통해 선언됩니다. 사실 이 정도면 기본적인 기능을 갖춘 스프레드쉬트를 만들기에 충분합니다. 이제 구성을 향상시키는 방법을 알아보겠습니다.
추가 도구 모음
테이블 관리 컨트롤이 포함된 앱 도구 모음부터 시작할 수 있습니다. 여기서 주목할 점은 기본 구성에서 툴바는 데이터 작업에 필요한 최소한의 컨트롤 집합만 표시한다는 것입니다.
확장된 컨트롤 집합을 사용하려면 도구 모음 속성을 지정하고 "전체" 값으로 설정해야 합니다. 코드에는 다음과 같이 표시됩니다.
{ view: "spreadsheet", toolbar: "full" }
브라우저에서 다음 결과를 볼 수 있습니다.
도구모음이 전혀 필요하지 않은 경우도 있습니다. 제거하려면 도구 모음 속성을 false로 설정합니다.
상단 메뉴
확장 도구 모음으로 작업하는 것이 항상 편리한 것은 아닙니다. 또한 화면 해상도가 작을 경우 일부 컨트롤이 숨겨질 수 있다는 점도 고려할 필요가 있습니다. 이 문제를 방지하려면 위젯 맨 위에 메뉴를 추가할 수 있습니다. 이렇게 하려면 구성 요소 구성에서 메뉴 속성을 지정하고 true로 설정해야 합니다. 코드에는 다음과 같이 표시됩니다.
{ view: "spreadsheet", menu: true }
브라우저에서는 다음 결과를 볼 수 있습니다.
수식 편집기
위에서 언급한 것처럼 위젯의 기능은 데스크톱 형에 뒤지지 않는다. 이를 입증하는 것은 엑셀에서 지원되는 데이터 작업을 위한 모든 공식이 완벽하게 지원된다는 것이다. 이 문서에서 자세한 설명이 포함된 전체 공식 목록을 찾을 수 있습니다.
또한 공식 작업을 위해 도구 모음 아래에 특수 편집기가 있습니다. 함수 이름을 입력하면 편집기에 입력된 문자에 해당하는 가능한 옵션 목록이 표시됩니다. 또한 수식이 적용되는 셀을 클릭하면 이 수식의 범위 내에 있는 모든 셀이 위젯에 강조 표시됩니다.
선택적으로 이 편집기를 숨길 수 있으며 수학 지원은 그대로 유지됩니다. 이렇게 하려면 위젯 생성자에서 liveEditor 속성을 false로 설정해야 합니다. 코드에는 다음과 같이 표시됩니다.
{ view: "spreadsheet", liveEditor: false }
아래쪽 막대
한 번에 여러 파일을 사용하여 작업하려면 기본적으로 숨겨져 있는 위젯의 아래쪽 막대를 활성화해야 합니다. 이 도움말로 새 시트를 작성할 수 있을 뿐만 아니라 기존 시트를 탐색할 수 있습니다.
이 패널을 표시하려면 병마 속성을 true로 설정하십시오. 코드에는 다음과 같이 표시됩니다.
{ view: "spreadsheet", bottombar: true }
브라우저에서 다음 결과를 볼 수 있습니다.
도구 모음의 확장 버전(도구 모음:"full")을 사용하는 경우 맨 아래 막대가 기본적으로 표시됩니다. 이를 숨기려면 보톰바 속성을 false로 설정합니다.
읽기 전용 모드
위젯을 사용하여 특정 정보만 표시해야 하는 경우도 있습니다. 이러한 경우 위젯은 읽기 전용 모드를 제공합니다.
이 기능을 사용하려면 읽기 전용 속성을 true로 설정하십시오. 이제 위젯은 현재 시트(테이블)가 있는 작업 영역만 표시합니다. 모든 추가 패널이 숨겨집니다. 코드에는 다음과 같이 표시됩니다.
{ view: "spreadsheet", readonly: true }
브라우저에서 다음 결과를 볼 수 있습니다.
데이터 로드 중
위젯 구성에서 처음 로드할 때 표시할 데이터를 지정할 수 있습니다. 데이터가 (클라이언트 또는 서버 쪽에) 위치함에 따라 데이터 또는 URL 속성 또는 구문 분석() 또는 로드() 방법을 사용해야 합니다. 이러한 각 옵션에 대해 자세히 살펴보겠습니다.
클라이언트 측 데이터 구문 분석
기본적으로 위젯은 JSON 형식의 데이터를 허용합니다. 데이터가 클라이언트 쪽에 있는 경우 데이터가 있는 개체에 데이터 속성을 설정하거나 구문 분석() 방법을 통해 동일한 데이터를 구문 분석할 수 있습니다.
데이터 개체에는 해당 파라미터를 설명할 수 있는 특정 필드가 포함됩니다.
데이터(셀 데이터)
스타일(셀 스타일링)
스팬 (세포 융합)
표(표 매개 변수)
기타 분야
이 문서에서 시트 설정의 전체 목록을 찾을 수 있습니다. 설정이 있는 개체는 다음과 같을 수 있습니다.
const sheet_data = { "styles": [ ["wss1",";;center;;;;;;;;;"], ... ], "sizes": [ [0,1,125], ], "data": [ [1,1,"Report - July 2016","wss1", "string"], [1,2,"","wss2"], ... ], "spans": [ [1,1,5,1] ] };
위젯 생성자에서 데이터 속성을 이 개체에 설정할 수 있습니다.
{ view: "spreadsheet", data: sheet_data }
또는 매개 변수로 구문 분석 메서드에 전달합니다.
{ view: "spreadsheet", id: "ssheet" } $$("ssheet").parse(sheet_data);
여기서 라이브 데모를 볼 수 있습니다.
서버측 데이터 로드 중
서버에서 원격 데이터를 로드해야 하는 경우 URL 속성을 원하는 파일이 위치한 해당 경로로 설정할 수 있습니다.
{ view: "spreadsheet", url: "sheet_data.js" }
또는 로드 검색 방법을 통해 데이터를 로드하여 해당 링크를 매개 변수로 전달합니다.
{ view: "spreadsheet", id: "ssheet" } $$("ssheet").load("sheet_data.js");
위젯이 다양한 형식의 데이터를 처리할 수 있다는 점을 명심해야 합니다. 예를 들어 CSV 형식으로 데이터를 로드해야 하는 경우 데이터 형식 속성을 필요한 형식으로 설정해야 합니다.
{ view: "spreadsheet", id: "ssheet", url: "sheet_data.csv", datatype: "csv" }
또는 두 번째 파라미터로 형식을 로드 계산 방법에 전달합니다.
$$("ssheet").load("sheet_data.csv", "csv");
여기서 라이브 데모를 볼 수 있습니다.
엑셀 형식의 데이터를 로드하려면 각별한 주의가 필요합니다. 데이터 형식 및 파일 경로 외에도 데이터를 로드할 이진 > 프록시 개체를 지정해야 합니다. 코드에는 다음과 같이 표시됩니다.
{ view: "spreadsheet", id: "ssheet", url: "binary->sheet_data.xlsx", datatype: "excel" }
또는 부하 측정 방법을 통해 동일한 방식으로:
$$("ssheet").load("binary->sheet_data.xlsx", "excel");
여기서 라이브 데모를 볼 수 있습니다.
데이터 저장
스프레드시트 위젯은 완전한 클라이언트측 앱입니다. 하지만 서버와 함께 작업할 수 있는 특별한 API도 있습니다. 서버 데이터 로딩에 대해 이전 섹션에서 몇 가지 언급했습니다.
또한 POST 방법을 통해 AJAX 요청이 전송될 서버 스크립트의 경로를 지정할 수 있습니다. 이 문제는 시트를 변경할 때 발생합니다.
이렇게 하려면 저장 속성의 개체에 있는 서버 스크립트 경로에 대한 모든 속성을 설정해야 합니다.
{ view: "spreadsheet", url: "server/get_data.php", save: { all: "/server" } }
여기서 라이브 데모를 볼 수 있습니다.
이제 시트를 변경하면 위젯의 상태를 포함한 모든 데이터가 자동으로 서버로 전송됩니다. 또한 특정 작업에 대한 전송 요청을 시트(데이터 추가, 이름 변경, 업데이트 또는 삭제)로 구성해야 하는 경우에는 RESTful 저장을 설정할 수 있습니다.
시트 변경 내용을 추적하려면 onChange 이벤트에 가입하여 처리기로 설정해야 합니다. 이 작업은 온 속성 개체에서 수행할 수 있습니다. 이 핸들러 내에서 일부 작업이 실행될 때 자동으로 전송되는 각 작업에 대해 별도의 요청을 설정할 수 있습니다. 이벤트 핸들러가 있는 위젯 코드는 다음과 같습니다.
const server_url = "server/get_data.php" { view: "spreadsheet", url: server_url, on:{ onChange: function(mode, name, oldName){ switch (mode) { case "update": webix.ajax().headers({ "Content-type" : "application/json" }).put(server_url+name, this.serialize()); break; case "rename": webix.ajax().headers({ "Content-type" : "application/json" }).put(server_url+oldName, {name:name}); break; case "remove": webix.ajax().headers({ "Content-type" : "application/json" }).del(server_url+name); break; case "insert": webix.ajax().headers({ "Content-type" : "application/json" }).post(server_url+name); } } } }
여기서 라이브 데모를 볼 수 있습니다.
이렇게 하면 서버에서 정보 저장을 구성할 수 있습니다. 위젯은 Node.js 백엔드와 함께 배포됩니다. 필요한 모든 데이터베이스에 쉽게 적용할 수 있습니다.
현지화
모든 웨빅스 위젯의 중요한 장점 중 하나는 위치 파악이 용이하다는 것입니다. 또한 기본적으로 모든 위젯 레이블은 영어로 지정된다는 점을 명확히 할 필요가 있습니다(en-US 로케일). 그러나 현재 로케일을 수정하거나 사용자 지정 로케일을 만들 수 있습니다. 이 두 가지 옵션을 모두 살펴보겠습니다.
현재 로케일 변경 방법
현재 로케일의 인터페이스 요소에 대한 모든 변환은 webix.i18n.spreadsheet 개체에 저장됩니다. 다음 인터페이스 요소를 현지화할 수 있습니다.
도구 모음의 모든 레이블
툴팁
모든 메뉴 항목
로케일 개체의 구조는 다음과 같습니다.
js export default { labels: { "common": "Common", "currency": "Currency", ..., }, tooltips: { "color": "Font color", "background" : "Background color", ... }, menus: { "remove-sheet": "Remove sheet", "rename-sheet": "Rename sheet", ... }, table: { "math-error": "#ERROR!", "Math-ref-error": "#REF!", ... }, liveEditor: { "edit": "Edit:" }, formats: { "dateFormat": "mm/dd/yyyy", "timeFormat": "hh:mm AM/PM", ... } };
현재 값을 사용자 지정 변환으로 바꾸기만 하면 위젯이 인터페이스에서 해당 값을 변경합니다. 보시다시피, 모든 것이 꽤 간단합니다. ### 사용자 지정 로케일 생성 방법 두 번째 방법에서는 구조가 동일한 사용자 지정 로케일을 만들어 전체 위젯에 적용해야 합니다. 이렇게 하려면 webix.i18n.locales[localeN] 스프레드시트 개체에 해당 변환을 추가하고 이름을 지정해야 합니다. ```js webix.i18n.locales["en-RU"].spreadsheet = { "labels": { "common": "General", "currency": "Currency", ... }, "tooltips": { "color": "Text color", "background": "Background color", ... }, ... }; ``` 새 로케일을 적용하려면 webix.i18n 개체의 setLocale() 메서드를 호출하여 사용자 지정 로케일 이름을 전달해야 합니다. ```js webix.i18n.setLocale("ru-RU"); ``` 여기서 라이브 데모를 볼 수 있습니다. 언제든지 원래 로케일로 전환할 수 있는 기능이 있으므로 이 방법을 사용하는 것이 좋습니다. 도서관에는 사용자가 번역을 게시할 수 있는 특별한 플랫폼이 있다는 점도 언급할 가치가 있다. 이 GitHub 저장소에서 체크아웃할 수 있습니다. 위젯 지역화에 참여하고 사용자 지정 로캘을 해당 리포지토리에 업로드할 수도 있습니다. ## 커스터마이징 기본 설정이 충분하지 않은 경우 위젯 인터페이스 및 기능을 사용자 정의할 수 있습니다. 이를 위해서는 위젯 코드를 조금 더 파고들어야 합니다. 인터페이스 및 기능 사용자 지정에 대한 몇 가지 관련 예제를 살펴보겠습니다. ### 추가 도구 모음 추가 방법 예를 들어, 도구 모음과 작업 영역 사이에 구성요소를 배치하고 동작을 사용자 정의할 수 있습니다. 이렇게 하려면 하위 표시줄 속성을 사용해야 합니다. 특정 구성 요소 또는 여러 구성 요소가 있는 레이아웃으로 설정할 수 있습니다. 명확성을 위해 다양한 형식(Excel, PNG, PDF 및 CSV)으로 데이터를 내보낼 수 있는 버튼이 있는 도구 모음을 추가해 보겠습니다. 도구 모음 생성자를 다른 변수에 저장하여 보다 편리하게 사용할 수 있습니다. 위젯 구성에서 하위 표시줄 속성을 이 변수로 설정해야 합니다. 코드에는 다음과 같이 표시됩니다. ```js const extra_toolbar = { view: "toolbar", css: "webix_ssheet_toolbar", elements:[ { view: "button", value: "Export to Excel", click: function(){ webix.toExcel("ssheet"); }, { view: "button", value: "Export to PNG", click: function(){ webix.toPNG("ssheet"); }, { view: "button", value: "Export to PDF", click: function(){ webix.toPDF("ssheet", {autowidth: true}); }, { view: "button", value: "Export to CSV", click: function(){ webix.toCSV("ssheet"); }, {} ] }; webix.ui({ id: "ssheet", view: "spreadsheet", subbar: extra_toolbar }); ``` 여기서 라이브 데모를 볼 수 있습니다. 이미 알고 있는 바와 같이 라이브러리는 위젯의 ID만 사용하는 데이터를 내보내는 특별한 방법을 제공합니다. 추가 도구 모음에서 해당 버튼을 클릭하면 데이터가 필요한 형식으로 다운로드됩니다. 브라우저에서 다음 결과를 볼 수 있습니다.  ### 상단 메뉴 사용자 정의 방법 위젯 구성을 통해 상단 메뉴를 사용자 지정할 수 있습니다. 명확성을 위해 일부 옵션을 제거하고 새 옵션을 추가하는 방법을 알아보겠습니다. 먼저 상단 메뉴의 옵션이 있는 배열을 만들어야 합니다. 편의를 위해 별도의 변수에 저장할 수 있습니다. ```js const custom_menu = [ { id: "file", submenu: [ {id: "excel-import"}, {id: "excel-export"} ]}, { id: "custom-options", value: "Custom Options", submenu: [ {id: "option-a", value: "Option A"}, {id: "option-b", value: "Option B"}, {id: "option-c", value: "Option C"} ] } ]; ``` 위의 코드에서 배열의 첫 번째 요소는 기본 제공 파일 옵션을 정의합니다. 옵션 드롭다운 목록은 Excel 형식의 데이터를 가져오고 내보내는 역할을 합니다. 두 번째 요소는 사용자 지정 옵션 항목이며 임의 옵션의 드롭다운 목록이 있습니다. 이제 메뉴 속성을 변수에 저장된 개체에 설정해야 합니다. ```js webix.ui({ view: "spreadsheet", menu: custom_menu }); ``` 브라우저에서는 다음 결과를 볼 수 있습니다.  ### 주 도구 모음 사용자 정의 방법 위젯 도구 모음은 블록으로 구성되며, 블록 안에는 특정 기능별로 그룹화된 단추가 있습니다. 이러한 블록(새 블록 숨기기, 표시 또는 추가)을 관리할 수 있을 뿐만 아니라 블록 내부의 버튼을 사용자 정의할 수 있습니다. 도구 모음 블록을 수정하려면 단추 모음에 해당하는 단추 속성을 사용해야 합니다. 이 컬렉션에는 키로 블록 이름과 값으로 단추 이름을 사용하는 배열이 포함되어 있습니다. 예를 들어 현재 도구 모음을 사용자 정의하고 기본 제공 블록을 두 개만 포함할 수 있을 뿐 아니라 사용자 지정 단추를 사용하여 새 블록을 추가할 수 있습니다. 코드에는 다음과 같이 표시됩니다. ```js { view: "spreadsheet", buttons: { "undo-redo": ["undo", "redo"], "format": ["format"], "Extra Block": [ { view: "button", width: 150, label: "Custom Button" } ] } } ``` 브라우저에서는 다음 결과를 볼 수 있습니다.  사용자 지정 도구 모음을 정의하려면 해당 설정이 있는 개체에 대해 도구 모음 속성(도구 모음 모음 참조)을 사용해야 합니다. 이 오브젝트 내에서 레이아웃 빌딩의 원리에 따라 사용자 정의 도구 모음 구조를 구성하고 크기, 들여쓰기, 스타일 등을 설정해야 합니다. 도구 모음 사용자 지정에 대한 자세한 내용은 관련 문서를 참조하십시오. 여기서 라이브 데모를 볼 수 있습니다. ## 결론 이 기사에서는 스프레드시트 위젯과 위젯의 주요 기능에 대해 배웠습니다. 사실, 이 출판물은 도구가 가지고 있는 모든 가능성 중 빙산의 일각만을 다루고 있다. 보시다시피 매우 기능적이고 유연한 구성요소입니다. 필요한 모든 프레임워크 또는 라이브러리와 쉽게 설정, 사용자 정의 및 통합할 수 있습니다. 백엔드와의 상호 작용을 설정할 수도 있습니다. 가능성과 사용자 지정에 대한 자세한 내용은 위젯 설명서를 참조하십시오.
from http://gong-tech.tistory.com/47 by ccl(A) rewrite - 2021-09-25 03:01:10