<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>yenny-y.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Thu, 14 Dec 2023 06:09:12 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <copyright>Copyright (C) 2019. yenny-y.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/yenny-y" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[NLog]]></title>
            <link>https://velog.io/@yenny-y/NLog</link>
            <guid>https://velog.io/@yenny-y/NLog</guid>
            <pubDate>Thu, 14 Dec 2023 06:09:12 GMT</pubDate>
            <description><![CDATA[<h2 id="nlog란">NLog란?</h2>
<blockquote>
<p>NLog is a flexible and free logging platform for various .NET platforms, including .NET standard.
NLog는 .NET standard 를 비롯한 다양한 .NET 플랫폼을 위한 유연하고 자유로운 로깅 플랫폼입니다.
<a href="https://nlog-project.org">https://nlog-project.org</a></p>
</blockquote>
<br>
<br>

<h2 id="configuration">Configuration</h2>
<p>config 파일을 사용하는 방법과 코드에서 설정하는 방법이 있습니다.
두가지 방법은 함께 사용할 수 있습니다.</p>
<h3 id="1-config-파일-사용">1. Config 파일 사용</h3>
<p>config 파일을 아래 순서대로 검색하다 처음 검색된 파일을 사용합니다.</p>
<blockquote>
<p><strong>독립 실행형 응용 프로그램 (.exe)</strong></p>
</blockquote>
<ul>
<li>표준 응용프로그램 구성 파일 app.config (ex: 프로그램명.exe.config)</li>
<li>응용 프로그램 폴더에 있는 &#39;프로그램명.exe.nlog&#39;</li>
<li>응용 프로그램 폴더에 있는 &#39;NLog.config&#39;</li>
<li>NLog.dll이 위치한 폴더에 있는 &#39;NLog.dll.nlog&#39;
(NLog.dll이 GAC(Global Assembly Cache)에 설치되지 않은 경우에만)</li>
</ul>
<hr>
<p><strong>ASP.NET 응용 프로그램</strong></p>
<ul>
<li>표준 응용 프로그램 구성 파일 &#39;web.config&#39;</li>
<li>web.config 파일이 위치한 폴더에 있는 &#39;web.nlog&#39;</li>
<li>응용 프로그램의 폴더에 있는 &#39;NLog.config&#39;</li>
<li>NLog.dll이 위치한 폴더에 있는 &#39;NLog.dll.nlog&#39;
(NLog.dll이 GAC(Global Assembly Cache)에 설치되지 않은 경우에만)</li>
</ul>
<h3 id="2-코드에서-설정">2. 코드에서 설정</h3>
<p>Configuration API 를 사용하여 프로그래밍 방식으로 코드에서 설정할 수 있습니다.
모든 속성은 config 파일의 구조와 동일합니다.</p>
<br>
<br>

<h2 id="config-파일">Config 파일</h2>
<h3 id="0-파일-구조">0. 파일 구조</h3>
<blockquote>
</blockquote>
<pre><code>&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot; ?&gt;
&lt;nlog xmlns=&quot;http://www.nlog-project.org/schemas/NLog.xsd&quot;
      xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;&gt;
&gt;      
    &lt;!-- 변수 선언 --&gt;
&gt;
    &lt;!-- Targets : 출력 대상 정의 --&gt;
    &lt;targets&gt;
    &lt;/targets&gt;
&gt;
    &lt;!-- Rules : 출력 정책 설정 --&gt;
    &lt;rules&gt;
    &lt;/rules&gt;
&lt;/nlog&gt;</code></pre><h3 id="1-기본-옵션">1. 기본 옵션</h3>
<blockquote>
</blockquote>
<pre><code>&lt;nlog xmlns=&quot;http://www.nlog-project.org/schemas/NLog.xsd&quot;
      xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
      autoReload=&quot;Boolean&quot;
      internalLogFile=&quot;String&quot;
      keepVariablesOnReload=&quot;Boolean&quot;/&gt;</code></pre><ul>
<li>autoReload (Boolean) : config 파일의 변경사항을 자동으로 다시 로드할지 여부</li>
<li>internalLogFile (String) : 내부 로그 파일 경로</li>
<li>keepVariablesOnReload (Boolean) : 런타임에 할당된 변수를 config 가 다시 로드될 때 유지할지 여부</li>
<li>그 외 : internalLogToConsole, internalLogToConsoleError, internalLogLevel, globalThreshold, throwExceptions, throwConfigExceptions, internalLogToTrace, internalLogIncludeTimestamp, useInvariantCulture, parseMessageTemplates</li>
</ul>
<h3 id="2-변수">2. 변수</h3>
<p>변수는 Configuration API 를 사용하여 변경, 삭제 및 생성할 수 있습니다.</p>
<blockquote>
<p><strong>변수 정의</strong></p>
</blockquote>
<pre><code>&lt;variable name=&quot;변수명&quot; value=&quot;값&quot;/&gt;</code></pre><p><strong>변수 사용</strong></p>
<pre><code class="language-bash">${변수명} - 정적 모드 (또는 상수 모드)
${var:변수명} - 동적 모드</code></pre>
<h3 id="3-targets">3. targets</h3>
<p>출력 대상과 레이아웃을 정의합니다.
대상 - 콘솔, 파일, DB, 메일, 클라우드, 로그 뷰어 (NLog, Log4j, Windows), 윈폼 등 (v5.2.7 기준 101개)
레이아웃 - 텍스트, JSON, CVS, Log4JXml, XML 등 (v5.2.7 기준 13개)
(<a href="https://nlog-project.org/config/?tab=targets">https://nlog-project.org/config/?tab=targets</a>)</p>
<blockquote>
</blockquote>
<p><strong>Console</strong></p>
<pre><code>&lt;target xsi:type=&quot;Console&quot;
        name=&quot;String&quot;
        layout=&quot;Layout&quot;
        autoFlush=&quot;Boolean&quot;
        error=&quot;Boolean&quot;/&gt;</code></pre><ul>
<li>name (String) - 대상 이름</li>
<li>layout (Layout) - 로그 메시지 형태</li>
<li>autoFlush (Boolean) - 콘솔 출력 후 자동 플러시 여부</li>
<li>error (Boolean) - 표준 출력 대신 표준 오류로 보낼지 여부</li>
<li>그 외 - header, footer, detectConsoleAvailable, encoding, writeBuffer, optimizeBufferReuse<blockquote>
<hr>
</blockquote>
</li>
<li><em>File*</em><pre><code>&lt;target xsi:type=&quot;File&quot;
       name=&quot;xs:string&quot;
       layout=&quot;Layout&quot;
       maxArchiveDays=&quot;Integer&quot;
       archiveEvery=&quot;Enum&quot;
       archiveAboveSize=&quot;Long&quot;
       maxArchiveFiles=&quot;Integer&quot;
       archiveOldFileOnStartup=&quot;Boolean&quot;
       fileName=&quot;Layout&quot;/&gt;</code></pre></li>
<li>name (String) - 대상 이름</li>
<li>layout (Layout) - 로그 메시지 형태</li>
<li>maxArchiveDays (Integer) - 아카이브 파일 보관 기간</li>
<li>archiveEvery (Enum) - 로그 파일 아카이빙 주기 (Day, Sunday 등)</li>
<li>archiveAboveSize (Long) - 로그 파일 아카이빙 크기 (바이트)</li>
<li>maxArchiveFiles (Integer) - 아카이브 파일의 최대 개수</li>
<li>archiveOldFileOnStartup (Boolean) - 시작 시 기존 로그 파일을 아카이빙할지 여부</li>
<li>fileName (Layout) - 파일명</li>
<li>그 외 - header, footer, encoding, lineEnding, enableArchiveFileCompression, archiveNumbering, archiveFileName, archiveFileKind, writeFooterOnArchivingOnly, maxLogFilenames, deleteOldFileOnStartup, fileAttributes, createDirs, cleanupFileName, archiveOldFileOnStartupAboveSize, archiveDateFormat, enableFileDelete, writeBom, replaceFileContentsOnEachWrite, forceMutexConcurrentWrites, forceManaged, fileNameKind, optimizeBufferReuse, networkWrites, openFileCacheTimeout, openFileCacheSize, keepFileOpen, discardAll, concurrentWrites, concurrentWriteAttempts, concurrentWriteAttemptDelay, bufferSize, openFileFlushTimeout, autoFlush<blockquote>
<hr>
</blockquote>
</li>
<li><em>Database*</em><pre><code>&lt;target xsi:type=&quot;Database&quot;
       name=&quot;String&quot;
       keepConnection=&quot;Boolean&quot;
       dbProvider=&quot;String&quot;
       dbHost=&quot;Layout&quot;
       dbDatabase=&quot;Layout&quot;
       dbUserName=&quot;Layout&quot;
       dbPassword=&quot;Layout&quot;
       connectionString=&quot;Layout&quot;
       commandText=&quot;Layout&quot;&gt;
&gt;
 &lt;parameter name=&quot;String&quot;
            layout=&quot;Layout&quot;
            format=&quot;String&quot;/&gt;
&lt;/target&gt;</code></pre></li>
<li>name (String) - 대상 이름</li>
<li>keepConnection (Boolean) - DB 연결 유지 여부</li>
<li>dbProvider (String) - DB 공급자 이름 (connectionString 미제공 시 &#39;Provider=&#39;)</li>
<li>dbHost (Layout) - DB 호스트명 (connectionString 미설정 시 &#39;Server=&#39;)</li>
<li>dbDatabase (Layout) - DB 이름 (connectionString 미설정 시 &#39;Database=&#39;)</li>
<li>dbUserName (Layout) - DB 사용자 이름 (connectionString 미설정 시 &#39;User ID=&#39;)</li>
<li>dbPassword (Layout) - DB 암호 (connectionString 미설정 시 &#39;Password=&#39;)</li>
<li>connectionString (Layout) - DB 연결 문자열</li>
<li>commandText (Layout) - SQL 명령어 (INSERT 쿼리 등)</li>
<li>parameter - SQL 명령어 파라미터</li>
<li>parameter/name (String) - 파라미터 이름</li>
<li>parameter/layout (Layout) - 파라미터 형태</li>
<li>그외 - keepConnection, connectionproperty, commandProperty, installConnectionString, install-command, uninstall-command, isolationLevel, optimizeBufferReuse, commandType, parameter/dbType, parameter/size, parameter/precision, parameter/scale, parameter/parameterType, parameter/allowDbNull, parameter/format, parameter/culture</li>
</ul>
<h3 id="4-rules">4. rules</h3>
<p>출력 대상이나 로그 레벨에 대한 출력 정책을 설정합니다.
로그 레벨 - Trace (0) &gt; Debug (1) &gt; Info (2) &gt; Warn (3) &gt; Error (4) &gt; Fatal (5)</p>
<blockquote>
</blockquote>
<pre><code>&lt;logger name=&quot;String&quot;
        levels=&quot;String&quot;
        minlevel=&quot;Enum&quot;
        maxlevel=&quot;Enum&quot;
        level=&quot;Enum&quot;
        writeTo=&quot;String&quot;
        final=&quot;Boolean&quot;
        enabled=&quot;Boolean&quot;
        ruleName=&quot;String&quot; /&gt;</code></pre><ul>
<li>name (String) - 로깅할 로거 이름 (*, ? 사용 가능)</li>
<li>levels (String) - 로깅할 레벨 목록 (&#39;,&#39;로 구분하여 나열)</li>
<li>minlevel (Enum) - 로깅할 최소 레벨</li>
<li>maxlevel (Enum) - 로깅할 최대 레벨</li>
<li>level (Enum) - 로깅할 레벨</li>
<li>writeTo (String) - 로깅할 출력 대상 이름 목록 (&#39;,&#39;로 구분하여 나열)</li>
<li>final (Boolean) - 일치하는 규칙이 있는 경우 이후 규칙 처리 중지 여부</li>
<li>enabled (Boolean) - 규칙 비활성화</li>
<li>ruleName (String) - 규칙 이름</li>
</ul>
<h3 id="5-레이아웃-렌더러">5. 레이아웃 렌더러</h3>
<p>레이아웃에서 사용되는 템플릿 매크로입니다.
(v5.2.7 기준 143개. <a href="https://nlog-project.org/config/?tab=layout-renderers">https://nlog-project.org/config/?tab=layout-renderers</a>)</p>
<blockquote>
</blockquote>
<pre><code class="language-bash">${level} - 로그 레벨
${message} - 로그 메시지</code></pre>
<pre><code class="language-bash">호출 위치 및 호출 스택
${callsite-filename} - 호출 파일명
${callsite-linenumber} - 호출 줄 번호
${stacktrace} - 스택 트레이스</code></pre>
<pre><code class="language-bash">조건
${when:when=조건:inner=값1:else=값2} - 조건에 따라 값 선택
${값:whenempty=대체값} - 값이 비어있을 경우 값 대체</code></pre>
<pre><code class="language-bash">컨텍스트 정보
${변수명} - NLog 로깅 변수값</code></pre>
<pre><code class="language-bash">카운터
${guid} - GUID
${sequenceid} - 로그 시퀀스 아이디</code></pre>
<pre><code class="language-bash">날짜 및 시간
${date}, ${longdate}, ${shortdate} - 현재 날짜 및 시간
${ticks} - 현재 날짜 및 시간의 ticks</code></pre>
<pre><code class="language-bash">인코딩 및 문자열 변환
${값:padding=개수} - 개수만큼 왼쪽 패딩
${replace:inner=값:searchFor=찾기:replaceWith=바꾸기} - 문자열 바꾸기
${substring:inner=값:start=N1:length=N2} - 문자열 자르기
${값:trimWhiteSpace=true} - 공백 제거
${값:uppercase=true}, ${lowercase:값} - 대/소문자 출력
${값:json-encode=true}, ${값:xmlEncode=true} - json/xml 인코딩</code></pre>
<pre><code class="language-bash">환경 및 구성 파일
${appsetting:item=이름} - app 설정 값 (app.config)
${environment:변수명} - 환경 변수 값</code></pre>
<pre><code class="language-bash">파일 및 디렉토리
${basedir}, ${processdir}, ${tempdir} - 디렉토리 경로
${file-contents:fileName=파일명} - 파일 내용</code></pre>
<pre><code class="language-bash">사용자 식별
${environment-user} - 사용자/도메인 정보</code></pre>
<pre><code class="language-bash">프로세스, 스레드 및 어셈블리
${appdomain} - app 도메인
${assembly-version} - 어셈블리 버전
${hostname} - 호스트 이름
${local-ip} - 로컬 IP 주소
${processid}, ${processname} - 프로세스 ID/이름
${threadid}, ${threadname} - 스레드 ID/이름</code></pre>
<br>
<br>

<h2 id="예제">예제</h2>
<h3 id="1-nuget-설치">1. NuGet 설치</h3>
<blockquote>
</blockquote>
<ul>
<li>NLog</li>
<li>NLog.Config (옵션)
<img src="https://velog.velcdn.com/images/yenny-y/post/2b3b221d-591d-471a-9051-04196dbf7ad9/image.png" alt=""></li>
</ul>
<h3 id="2-nlogconfig-작성">2. NLog.config 작성</h3>
<blockquote>
<pre><code>&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot; ?&gt;
&lt;nlog xmlns=&quot;http://www.nlog-project.org/schemas/NLog.xsd&quot;
      xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;&gt;
  &lt;variable name=&quot;logLayout&quot; value=&quot;[${date:format=HH\:mm\:ss.fff}] | ${level:padding=-5} | ${message}&quot;/&gt;
  &lt;variable name=&quot;logDir&quot; value=&quot;${currentdir}\log\${date:format=yyyyMMdd_HH}&quot;/&gt;
</code></pre></blockquote>
  <targets>
    <target xsi:type="Console" name="console" layout="${stacktrace} ${var:logLayout}"/>
    <target xsi:type="File" name="file" layout="${var:logLayout}" fileName="${var:logDir}\log_${date:yyyyMMdd}.txt" maxArchiveDays="1"/>
    <target xsi:type="File" name="file-err" layout="${callsite-filename} ${callsite-linenumber} ${var:logLayout}" fileName="${var:logDir}\log_${date:yyyyMMdd}_err.txt" archiveOldFileOnStartup="True"/>
>
  <rules>
    <logger writeTo="console"/>
    <logger minlevel="Info" maxlevel="Error" writeTo="file"/>
    <logger level="Error" writeTo="file-err"/>
  </rules>
</nlog>
```


<h3 id="3-코드-작성">3. 코드 작성</h3>
<blockquote>
</blockquote>
<pre><code class="language-cs">using NLog;
&gt;
namespace NLogTest
{
    class Program
    {
        private static Logger _logger = LogManager.GetCurrentClassLogger();
        static void Main(string[] args)
        {
            _logger.Debug(&quot;[Main] Debug 로그&quot;);
            _logger.Info(&quot;[Main] Info 로그&quot;);
            _logger.Error(&quot;[Main] Error 로그&quot;);
            _logger.Fatal(&quot;[Main] Fatal 로그&quot;);
&gt;
            Test1();
        }
&gt;
        static void Test1()
        {
            _logger.Debug(&quot;[Test1] Debug 로그&quot;);
            _logger.Info(&quot;[Test1] Info 로그&quot;);
            _logger.Error(&quot;[Test1] Error 로그&quot;);
            _logger.Fatal(&quot;[Test1] Fatal 로그&quot;);
&gt;
            Test2();
        }
&gt;
        static void Test2()
        {
            _logger.Debug(&quot;[Test2] Debug 로그&quot;);
            _logger.Info(&quot;[Test2] Info 로그&quot;);
            _logger.Error(&quot;[Test2] Error 로그&quot;);
            _logger.Fatal(&quot;[Test2] Fatal 로그&quot;);
        }
    }
}</code></pre>
<h3 id="4-결과">4. 결과</h3>
<blockquote>
<p><strong>Console</strong>
<img src="https://velog.velcdn.com/images/yenny-y/post/8cf1d644-2c87-46c0-bc01-477f3f595d84/image.png" alt=""></p>
</blockquote>
<pre><code>&lt;target xsi:type=&quot;Console&quot; name=&quot;console&quot; layout=&quot;${stacktrace} ${var:logLayout}&quot;/&gt;
&lt;logger writeTo=&quot;console&quot;/&gt;</code></pre><ul>
<li>모든 레벨 출력</li>
<li>스택 트레이스 출력 (Program.Main =&gt; Program.Test1 =&gt; Program.Test2)</li>
</ul>
<hr>
<p><strong>File</strong>
<img src="https://velog.velcdn.com/images/yenny-y/post/362e7e13-1c59-4e6c-baf0-d5383e38795a/image.png" alt=""></p>
<pre><code>&lt;target xsi:type=&quot;File&quot; name=&quot;file&quot; layout=&quot;${var:logLayout}&quot; fileName=&quot;${var:logDir}\log_${date:yyyyMMdd}.txt&quot; maxArchiveDays=&quot;1&quot;/&gt;
&lt;logger minlevel=&quot;Info&quot; maxlevel=&quot;Error&quot; writeTo=&quot;file&quot;/&gt;</code></pre><ul>
<li>Info ~ Error 레벨 로그 출력<blockquote>
</blockquote>
<img src="https://velog.velcdn.com/images/yenny-y/post/caf3c6bf-68d3-4dfe-9b70-57b994b88fb9/image.png" alt=""><pre><code>&lt;target xsi:type=&quot;File&quot; name=&quot;file-err&quot; layout=&quot;${callsite-filename} ${callsite-linenumber} ${var:logLayout}&quot; fileName=&quot;${var:logDir}\log_${date:yyyyMMdd}_err.txt&quot; archiveOldFileOnStartup=&quot;True&quot;/&gt;
&lt;logger level=&quot;Error&quot; writeTo=&quot;file-err&quot;/&gt;</code></pre></li>
<li>Error 레벨 로그 출력</li>
<li>호출 파일명 및 줄 번호 출력 (C:\Source\NLogTest\NLogTest\Program.cs 32)</li>
</ul>
<hr>
<p>  2023.12.20 2회 실행
  <img src="https://velog.velcdn.com/images/yenny-y/post/1edd42bc-7809-4f6c-b9e2-c0f5e7ef41c8/image.png" alt="">
  2023.12.23 1회 실행
  <img src="https://velog.velcdn.com/images/yenny-y/post/2483780b-5c81-4b61-98c9-602ae22c21ab/image.png" alt=""></p>
<pre><code>&lt;target xsi:type=&quot;File&quot; name=&quot;file&quot; layout=&quot;${var:logLayout}&quot; fileName=&quot;${var:logDir}\log_${date:yyyyMMdd}.txt&quot; maxArchiveDays=&quot;1&quot;/&gt;
&lt;target xsi:type=&quot;File&quot; name=&quot;file-err&quot; layout=&quot;${callsite-filename} ${callsite-linenumber} ${var:logLayout}&quot; fileName=&quot;${var:logDir}\log_${date:yyyyMMdd}_err.txt&quot; archiveOldFileOnStartup=&quot;True&quot;/&gt;</code></pre><ul>
<li>보관 기간이 지난 아카이브 파일 자동 삭제 (log_20231220.txt)</li>
<li>시작 시 기존 로그 파일 아카이빙 (log_20231220_err.txt -&gt; log_20231220_err.0.txt)</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[CCTV 통합관제 솔루션 (VMS)]]></title>
            <link>https://velog.io/@yenny-y/NGVMS</link>
            <guid>https://velog.io/@yenny-y/NGVMS</guid>
            <pubDate>Mon, 03 Jul 2023 01:00:35 GMT</pubDate>
            <description><![CDATA[<h3 id="project">Project</h3>
<p>개발 기간 | 1 년
개발 환경 | WPF / Telerik
기능 요약 | CCTV 통합관제
주요 기능 | 1. CCTV 모니터링 및 관리
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2. PTZ 제어 및 영상 조정
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3. 영상 백업 및 재생
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;4. 객체 인식 이벤트 관리
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;5. 사용자 계정 관리</p>
<BR/>

<h3 id="기능">기능</h3>
<p>CCTV 관리 및 CCTV에서 촬영한 영상을 모니터링 하는 통합관제 솔루션입니다.
카메라 PTZ 제어 및 영상 조정 기능과 영상 백업 및 재생 기능을 제공합니다.
또한 AI선별관제 솔루션과 연동하여 객체(사람/차량) 인식 이벤트를 표시하는 기능을 지원합니다.
사용자 계정 관리를 통해 계정별로 기능 사용에 대한 권한을 부여할 수 있습니다.</p>
<BR/>

<h3 id="화면">화면</h3>
<p>영상 및 타임라인 화면은 외부 모듈을 사용했고, 그 외 부분은 WPF로 구현했습니다.</p>
<h4 id="공통">공통</h4>
<ul>
<li>트리 패널</li>
<li>이벤트 패널
<img src="https://velog.velcdn.com/images/yenny-y/post/a0f2b51d-2eed-4f4e-af2d-72d73cc4dc78/image.png" alt=""></li>
</ul>
<h4 id="관제-모드">관제 모드</h4>
<ul>
<li>CCTV 영상 및 타임라인</li>
<li>달력 및 플레이백 제어</li>
<li>카메라 PTZ 제어
<img src="https://velog.velcdn.com/images/yenny-y/post/dae7fe36-0e80-4f28-816f-0bc2cae3e7c7/image.png" alt=""></li>
</ul>
<h4 id="관리자-모드">관리자 모드</h4>
<ul>
<li>리소스 (레코딩 서버, 카메라 등) 관리</li>
<li>녹화 설정</li>
<li>사용자 계정 관리</li>
<li>AI선별관제 솔루션 연동 관리
<img src="https://velog.velcdn.com/images/yenny-y/post/4f59fc7b-07ad-4329-a998-726860eeac75/image.png" alt=""></li>
</ul>
<h4 id="기타">기타</h4>
<ul>
<li>로컬 프로그램 설정</li>
<li>카메라 정보 불러오기
<img src="https://velog.velcdn.com/images/yenny-y/post/cc46f7a2-9f36-436a-b121-032df34b0b90/image.png" alt=""></li>
</ul>
<BR/>

<h3 id="세부-화면">세부 화면</h3>
<ul>
<li>트리
<img src="https://i.ibb.co/mt4Dkcz/TreeView.gif" alt=""></li>
<li>리스트
<img src="https://i.ibb.co/KL31Xbz/GridView.gif" alt=""></li>
<li>PTZ 제어
<img src="https://i.ibb.co/Jj2jXSK/PTZ.gif" alt=""></li>
<li>Open/Close 토글 버튼
<img src="https://i.ibb.co/jVHPyxf/Open-Close.gif" alt=""></li>
<li>On/Off 토글 버튼
<img src="https://i.ibb.co/vDRmLLJ/Enable.gif" alt=""></li>
</ul>
<BR/>

<h3 id="담당-업무">담당 업무</h3>
<p>MVVM 패턴의 구조 설계와 전반적인 UI 구현을 담당했습니다.</p>
<h4 id="1-ui-구현">1. UI 구현</h4>
<p>디자인에 중점을 두기 위해 View와 ViewModel/Model 이 최대한 분리되도록 구현했습니다.
또한 Control 마다 스타일을 정의해 사용하여 통일된 스타일이 적용되도록 했습니다.</p>
<h4 id="2-back-end-모듈-연동">2. Back-End 모듈 연동</h4>
<p>Google Flatbuffers, C++/CLI, REST API 형태의 Back-End 모듈과 연동하는 기능을 구현했습니다.</p>
<pre><code>Google Flatbuffers
- 레코딩 서버, 카메라 정보 등 필요한 리소스 정보를 요청하고 Callback 형태로 정보를 수신받습니다.

C++/CLI
- 카메라 PTZ 제어 및 영상 조정 기능을 호출할 수 있습니다. (ONVIF)
- 카메라 이벤트를 수신받습니다.

REST API
- AI 선별관제 솔루션에 로그인하고 시나리오를 편집할 수 있습니다.</code></pre><BR/>

<h4 id="3-이벤트-메시지-수신-tcp">3. 이벤트 메시지 수신 (TCP)</h4>
<p>AI 선별관제에서 송신하는 이벤트 메시지를 수신받는 TCP 서버를 구현했습니다.
수신받은 이벤트는 일정 시간마다 카메라 별로 Grouping 하여 화면에 표시됩니다.</p>
<BR/>


<h4 id="4-다국어-기능">4. 다국어 기능</h4>
<p>언어별로 리소스 파일을 분리해 추가 및 수정에 용이하도록 구현했습니다.
언어 변경 시 로그아웃이나 프로그램 재실행 없이 런타임으로 설정이 가능합니다.
<img src="https://i.ibb.co/KWrvhvM/Switch-Language.gif" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[판서 애니메이션]]></title>
            <link>https://velog.io/@yenny-y/WhiteboardAnimation</link>
            <guid>https://velog.io/@yenny-y/WhiteboardAnimation</guid>
            <pubDate>Thu, 22 Apr 2021 19:40:38 GMT</pubDate>
            <description><![CDATA[<h3 id="project">Project</h3>
<p>개발 기간 | 3 개월
개발 환경 | WPF
기능 요약 | 이미지 파일의 문자를 인식해 판서 애니메이션 생성 및 실행
주요 기능 | 1. 이미지 파일의 문자 인식
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2. 판서 애니메이션 자동 생성 / 수동 Edit
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3. 판서 애니메이션 실행</p>
<BR/>

<h3 id="기능">기능</h3>
<p>이미지 파일의 문자를 인식해 판서 애니메이션을 자동으로 생성하고 실행하는 프로그램입니다.
애니메이션을 수동으로 Edit 하는 기능과, 결과물을 파일 형태로 저장 및 Load 하는 기능을 제공합니다.
여러개의 이미지 파일을 처리하고 애니메이션 할 수 있습니다.</p>
<BR/>

<h3 id="화면">화면</h3>
<p>MahApps.Metro와 MaterialDesignThemes를 사용했습니다.
전체적인 구조는 프로그램의 사용 Flow에 맞게 구성했고, Edit 프로그램 특성상 다양한 기능들이 있기 때문에 편의성을 위해 그림판 등의 익숙한 UI를 참고했습니다.</p>
<h4 id="project-1">PROJECT</h4>
<ul>
<li>대상/배경/펜 이미지 열기</li>
<li>OCR 분석</li>
<li>파일 저장/불러오기</li>
</ul>
<img src="https://i.ibb.co/RzYjSrz/Project.gif" alt="Project" border="0">

<h4 id="edit">EDIT</h4>
<ul>
<li>애니메이션 Edit</li>
<li>화면 옵션 설정 (View/Hide, 색상)</li>
</ul>
<img src="https://i.ibb.co/pb9dBB5/Edit.gif" alt="Edit" border="0">

<h4 id="animation">ANIMATION</h4>
<ul>
<li>프로젝트별 애니메이션 재생</li>
<li>전체 화면에서 애니메이션 재생</li>
<li>재생 속도 설정</li>
</ul>
<img src="https://i.ibb.co/RPpLCDd/Animation.gif" alt="Animation" border="0">
<img src="https://i.ibb.co/SyGNjHT/Animation-Full-Screen.gif" alt="Animation-Full-Screen" border="0">

<h4 id="expander">Expander</h4>
<ul>
<li>프로젝트 목록</li>
<li>애니메이션 목록</li>
<li>애니메이션의 Path 목록</li>
<li>애니메이션 Group 목록</li>
</ul>
<img src="https://i.ibb.co/m8j6T8y/Expander.gif" alt="Expander" border="0">

<BR/>

<h3 id="담당-업무">담당 업무</h3>
<h4 id="1-애니메이션-edit">1. 애니메이션 Edit</h4>
<p>애니메이션 Edit 기능을 개발했습니다.</p>
<ul>
<li>기능 목록<ul>
<li>선택 모드 (단일 선택 / 다중 선택)</li>
<li>영역 편집 (사각형 / 자유형)</li>
<li>편의 기능 (Merge / Sort)</li>
<li>애니메이션 추가</li>
<li>애니메이션 Path 편집 (지우개 / 펜 / 펜 색상)</li>
<li>애니메이션 Group 편집</li>
</ul>
</li>
</ul>
<blockquote>
<ul>
<li>선택 모드<ul>
<li>단일 선택<img src="https://i.ibb.co/41Pk1bS/Select-Single.gif" alt="Select-Single" border="0">
- 다중 선택
<img src="https://i.ibb.co/3Sy3jNx/Select-Multiple.gif" alt="Select-Multiple" border="0">

</li>
</ul>
</li>
</ul>
</blockquote>
<ul>
<li>영역 편집<ul>
<li>사각형<img src="https://i.ibb.co/w0bb1Tv/RectMode.gif" alt="RectMode" border="0">
- 자유형
<img src="https://i.ibb.co/njrKk4m/Custom-Mode.gif" alt="Custom-Mode" border="0">
>    </li>
</ul>
</li>
<li>편의 기능<ul>
<li>Merge<img src="https://i.ibb.co/7NGBFfm/Merge.gif" alt="Merge" border="0"></li>
<li>Sort (왼쪽 -&gt; 오른쪽 순서로 Sequence Number 정렬)<img src="https://i.ibb.co/6n2cXcs/Sort.gif" alt="Sort" border="0">
>    </li>
</ul>
</li>
<li>애니메이션 Path 편집<ul>
<li>지우개 (Path 영역이 지워지면서 원본 이미지가 보임)<img src="https://i.ibb.co/cXyhhP1/Erase.gif" alt="Erase" border="0"></li>
<li>펜 (원본 이미지 위에 추가)<img src="https://i.ibb.co/dDxn7vZ/Pen.gif" alt="Pen" border="0">

</li>
</ul>
</li>
</ul>
<BR/>

<h4 id="2-db-기능-개발">2. DB 기능 개발</h4>
<p>생성한 애니메이션을 .zip 형태의 파일로 저장하고 불러오는 기능을 개발했습니다.
<BR/></p>
<h3 id="참고">참고</h3>
<ul>
<li><p>문자 인식
이미지 파일의 문자 인식은 Tesseract 라이브러리를 사용했는데, 이미지 파일의 해상도에 따라 문자 인식률이 달라졌습니다.
인식률이 높을수록 자동으로 생성되는 애니메이션의 완성도가 높아지기 때문에 인식률을 높이기 위해 해상도를 단계별로 처리했습니다.</p>
<BR/>
</li>
<li><p>Layer 구조
<img src="https://images.velog.io/images/yenny-y/post/90bcd13c-5919-4137-aa47-71da5e427830/image.png" alt=""></p>
</li>
</ul>
<BR/>

<ul>
<li>지우개 Path 애니메이션 재생 단계
1) Cover Layer : Path 영역을 지움
2) Mask Layer : Path 영역을 배경 이미지로 채움
3) Path 에서 재생할 영역만 Mask Layer 를 지움
4) Mask Layer의 지워진 부분(3번)의 Source 이미지가 보임
5) 한 개의 Path가 다 재생될 때까지 3~4번 반복</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[교과/수능 성적 관리]]></title>
            <link>https://velog.io/@yenny-y/TheSchool</link>
            <guid>https://velog.io/@yenny-y/TheSchool</guid>
            <pubDate>Wed, 21 Apr 2021 08:31:36 GMT</pubDate>
            <description><![CDATA[<h3 id="project">Project</h3>
<p>개발 기간 | 2.5 개월
개발 환경 | WPF / MariaDB / NSIS
기능 요약 | 교과/수능 성적 관리
주요 기능 | 1. Excel 형태의 성적 데이터 DB 저장
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2. 최신 성적 데이터 관리
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3. 설치 패키지 제공
<BR/></p>
<h3 id="기능">기능</h3>
<p>Excel 형태의 성적 데이터를 DB에 저장하고, 서버 DB를 통해 사용자들의 성적 DB를 최신 성적으로 관리해주는 프로그램입니다.
DB 설치, DB 환경 구성, DB 삭제 (Uninstall) 기능을 포함하는 설치 패키지를 제공합니다.</p>
<BR/>

<h3 id="화면">화면</h3>
<p>UI 디자인은 클라이언트 쪽에서 직접 개발할 예정으로, 디자인은 제외하고 MVVM 패턴 적용과 주요 기능을 개발하는 것이 클라이언트의 요구사항이었습니다.
MahApps.Metro의 기본 Control을 사용했고 서버용 프로그램과 사용자용 프로그램 구분을 위해 색상을 다르게 적용했습니다.</p>
<h4 id="로그인">로그인</h4>
<p>&lt;서버용&gt;
<img src="https://images.velog.io/images/yenny-y/post/77d1d153-ef6d-42c6-8373-cc58f347c751/image.png" alt="">
&lt;사용자용&gt;
<img src="https://images.velog.io/images/yenny-y/post/7523ea49-73d8-4e63-a99b-9c8f46c5093e/image.png" alt=""></p>
<h4 id="성적-data-등록">성적 Data 등록</h4>
<p><img src="https://images.velog.io/images/yenny-y/post/32a607bb-d660-4e93-9479-0b816beb9405/image.png" alt=""></p>
<h4 id="교과-성적-조회">교과 성적 조회</h4>
<p><img src="https://images.velog.io/images/yenny-y/post/0b840e1f-b26f-45e2-9324-96ea56da0c8a/image.png" alt=""></p>
<h4 id="수능-성적-조회">수능 성적 조회</h4>
<p><img src="https://images.velog.io/images/yenny-y/post/1429922f-50f2-4733-a20e-4fa72fcff477/image.png" alt=""></p>
<h4 id="alert">Alert</h4>
<p><img src="https://images.velog.io/images/yenny-y/post/90ced290-1180-47c0-aa49-20ef4220a5f7/image.png" alt=""></p>
<h4 id="progress">Progress</h4>
<p><a><img src="https://i.ibb.co/L5KG8Cs/Progress.gif" alt="Progress" border="0"></a></p>
<BR/>

<h3 id="담당-업무">담당 업무</h3>
<h4 id="1-db-설계">1. DB 설계</h4>
<p>서버에서 사용자들에게 최신 성적 데이터를 제공하기 위해 성적 데이터 Update 상태를 관리하는 구조로 구성했습니다.
기존의 학생+성적 Table을 학생 정보와 성적 데이터로 분리해 중복 데이터를 제거했습니다.
<BR/></p>
<h4 id="2-db-기능-개발">2. DB 기능 개발</h4>
<p>대량의 데이터를 빠르게 저장하기 위해 Bulk Insert 와 Duplicate Key Update 쿼리를 사용했습니다.</p>
<pre><code class="language-sql">// insert 쿼리 (예시)
INSERT INTO score
(id, grade, part, name, lname, unit, avg, achive, rank)
VALUES 
(&#39;3010001&#39;, 1, 1, &#39;국어&#39;, &#39;독서와문법&#39;, 4, &#39;50/72.9(17.2)&#39;, &#39;E(379)&#39;, &#39;1&#39;),
(&#39;3010001&#39;, 1, 2, &#39;국어&#39;, &#39;독서와문법&#39;, NULL, NULL, NULL, NULL),
(&#39;3010001&#39;, 1, 1, &#39;국어&#39;, &#39;국어Ⅱ&#39;, NULL, NULL, NULL, NULL),
ON DUPLICATE KEY UPDATE
name = VALUES(name), unit = VALUES(unit), avg = VALUES(avg), achive = VALUES(achive), rank = VALUES(rank)</code></pre>
<BR/>

<h4 id="3-설치-패키지-생성">3. 설치 패키지 생성</h4>
<p>NSIS를 이용해 하나의 설치 패키지로 서버용과 사용자용을 선택 설치할 수 있는 설치 패키지를 생성했습니다.
프로그램 실행에 필요한 Database 및 Table을 생성하는 Console 프로그램을 개발해 설치 패키지에 포함시켰습니다.</p>
<ul>
<li><p>설치 옵션 선택
<img src="https://images.velog.io/images/yenny-y/post/77700503-113f-4e65-a981-92861f399691/image.png" alt=""></p>
</li>
<li><p>Install 구성
1) .NET Framework
2) MariaDB 자동 설치
3) DB 환경 구성
4) 교과/수능 성적 관리 프로그램</p>
</li>
<li><p>Uninstall 구성
1) MariaDB 자동 삭제
2) 교과/수능 성적 관리 프로그램 삭제</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[SSD Toolbox]]></title>
            <link>https://velog.io/@yenny-y/SSDToolbox</link>
            <guid>https://velog.io/@yenny-y/SSDToolbox</guid>
            <pubDate>Sat, 17 Apr 2021 09:13:56 GMT</pubDate>
            <description><![CDATA[<h3 id="project">Project</h3>
<p>개발 기간 | 2.5 개월
개발 환경 | WPF / NSIS
기능 요약 | Disk 정보 확인 및 Data Migration
주요 기능 | 1. Disk Information
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2. S.M.A.R.T 정보
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3. Data Migration
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;4. 설치 패키지 제공</p>
<BR/>

<h3 id="기능">기능</h3>
<p>Disk 상태와 S.M.A.R.T 정보를 확인하고 Data Migration 기능을 제공하는 프로그램입니다.
Disk 상태 및 S.M.A.R.T 정보는 SATA와 NVMe를 지원하고, Data Migration 은 Data Cloning 과 Boot Section 생성 기능을 지원합니다.</p>
<BR/>

<h3 id="화면">화면</h3>
<p>디자인 가이드를 제공 받았고 대부분의 Control 을 UserControl로 생성하고 Style을 정의해 사용했습니다.</p>
<h4 id="disk-information">Disk Information</h4>
<p><img src="https://images.velog.io/images/yenny-y/post/6194e329-b5e5-4f58-b1cf-1348e65b736f/image.png" alt=""></p>
<h4 id="smart">S.M.A.R.T</h4>
<p><img src="https://images.velog.io/images/yenny-y/post/6bf57245-fbdc-41a5-b284-f482958bb68b/image.png" alt=""></p>
<h4 id="data-migration">Data Migration</h4>
<p><img src="https://images.velog.io/images/yenny-y/post/92cb68b8-711d-4253-a376-3356274cb552/image.png" alt=""></p>
<h4 id="디자인-가이드">디자인 가이드</h4>
<p><img src="https://images.velog.io/images/yenny-y/post/c74ed866-f837-4b5d-aa15-6fa69121d207/image.png" alt=""></p>
<h4 id="구현-화면">구현 화면</h4>
<img src="https://i.ibb.co/fDsYTWk/ezgif-com-gif-maker.gif" alt="ezgif-com-gif-maker" border="0">
<img src="https://i.ibb.co/PjxbVW0/ezgif-com-gif-maker.gif" alt="ezgif-com-gif-maker" border="0">
<img src="https://i.ibb.co/MBtz81M/DataGrid.gif" alt="DataGrid" border="0">

<BR/>

<h3 id="담당-업무">담당 업무</h3>
<h4 id="1-data-migration">1. Data Migration</h4>
<p>Windows 7/10, 32Bit/64Bit 환경에서 Data Cloning 기능과 MBR/GPT Format의 부팅 기능을 개발했습니다.</p>
<ul>
<li><p>Data Migration (예시)</p>
<img src="https://i.ibb.co/qy9X9bH/Data-Migration.gif" alt="Data-Migration" border="0">
</li>
<li><p>Data Cloning
1) Data Cloning 조건 확인 : Source Disk 와 Target Disk 상태 확인
2) Target Disk 상태 변경 : Lock &gt; Offline
3) Disk Cloning
4) Target Disk 상태 변경 : Online &gt; Unlock &gt; Update Properties
참고 : <a href="https://github.com/TalAloni/RawDiskCopier">https://github.com/TalAloni/RawDiskCopier</a></p>
</li>
<li><p>Boot Section 생성
1) MBR/GPT 확인
2) Booting 가능 드라이버 확인
3) Boot Section 생성
참고 및 사용 : WMI, DISKPART, BCDEDIT</p>
</li>
</ul>
<BR/>

<h4 id="2-nvme">2. NVMe</h4>
<p>NVMe S.M.A.R.T 정보 화면과 기능을 개발했습니다.
NVMe 정보는 C++로 기능을 구현해 DLL 형태로 사용했습니다.
참고 : <a href="https://crystalmark.info/en/">https://crystalmark.info/en/</a></p>
<ul>
<li>NVMe S.M.A.R.T 정보 (예시)<img src="https://i.ibb.co/hDwV5Gq/NVMe-Smart-Info.gif" alt="NVMe-Smart-Info" border="0">

</li>
</ul>
<BR/>

<h4 id="3-설치-패키지-생성">3. 설치 패키지 생성</h4>
<p>NSIS 를 이용해 설치 패키지를 생성했습니다.</p>
<ul>
<li>설치 패키지 구성
1) VC++ 재배포 패키지 (x86/x64)
2) .NET Framework
3) SSD Toolbox</li>
</ul>
]]></description>
        </item>
    </channel>
</rss>