<![CDATA[ $ sh blog.update.sh ]]> https://blog.update.sh https://blog.update.sh/favicon.png $ sh blog.update.sh https://blog.update.sh Tue, 19 Mar 2024 16:23:40 +0900 60 <![CDATA[ 2024-03-18 주간 URL 모음 ]]> https://blog.update.sh/posts/weekly-urls-2024-03-18/ 65ee77ea5a1572000145f761 Mon, 18 Mar 2024 08:00:31 +0900
  • Claude 3 모델 공개 | GeekNews
  • Autoflow | Figma Community
  • Custom interactive maps for your business - Mapplic
  • 사이드 프로젝트는 사이드가 아니다 | 우아한형제들 기술블로그
  • 미 의회, TikTok 매각을 강제하거나 또는 앱을 금지하는 법안 통과 | GeekNews
  • betwixt-labs/bebop: 🎷No ceremony, just code. Blazing fast, typesafe binary serialization.
  • Detect Caps Lock with JavaScript
  • Show HN: Flox 1.0 – Nix를 활용한 오픈소스 개발 환경 코드화 | GeekNews
  • A world from a sheet of paper (2023) [video] | Hacker News
  • Figure Status Update - OpenAI Speech-to-Speech Reasoning - YouTube
  • ]]>
    <![CDATA[ 2024-03-11 주간 URL 모음 ]]> https://blog.update.sh/posts/weekly-urls-2024-03-11/ 65e56fad5a1572000145f71e Mon, 11 Mar 2024 08:00:03 +0900
  • 소프트웨어 개발에서 배운 교훈들 | GeekNews
  • Real gaming router | KittenLabs
  • Yuzu 개발자가 Nintendo의 소송에 대해 240만 달러에 합의했습니다. | GeekNews
  • Apple, M3 칩을 탑재한 MacBook Air 13 및 15 공개 | GeekNews
  • Observable Framework에서 나타난 흥미로운 아이디어들 | GeekNews
  • Please, enough with the dead butterflies! - Emily S. Damstra
  • Locofy.ai - ship your products 10x faster — with low code
  • GitHub besieged by millions of malicious repositories in ongoing attack | Ars Technica
  • 1Password의 패스키: 패스워드리스 인증의 미래 | 1Password
  • zhanymkanov/fastapi-best-practices: FastAPI Best Practices and Conventions we used at our startup
  • Microsoft WSA에서 더이상 Amazon Appstore는 지원하지않습니다 | GeekNews
  • 뉴욕 타임즈, 수백 개의 비공식 'Wordle' 클론에 대한 단속 강화 | GeekNews
  • Array languages vs. the curse of the spreadsheet — Elias Mårtenson
  • F. C. Variable: Rob en Robin create customisable illustrations inspired by variable fonts | Creative Boom
  • Sliders degrade UX (so do this instead) – Adam Silver – designer, London, UK
  • (번역) 수많은 저장소를 하나로: 자바스크립트 코드를 모노레포로 이동하기
  • 소통에 진심인 버추얼 아이돌을 만나볼 시간! – 컴투스온
  • Television for Vision Pro | GeekNews
  • Behind the Feature: The Multiple Lives of Multi-Edit | Figma Blog
  • ]]>
    <![CDATA[ 2024-03-04 주간 URL 모음 ]]> https://blog.update.sh/posts/weekly-urls-2024-03-04/ 65dbea9e5a1572000145f6d7 Mon, 04 Mar 2024 08:00:54 +0900
  • 인플루언서 마케팅 ROI: 팔로워 수가 적은 인플루언서가 더 비용 효과적임 | GeekNews
  • 2899: Goodhart's Law - explain xkcd
  • Tesla shares more footage of Optimus walking improvements
  • electric-sql/pglite: Lightweight Postgres packaged as WASM into a TypeScript library for the browser, Node.js, Bun and Deno
  • It's OK to abandon your side-project - Robb Owen
  • CSS 가상 선택자로 폼 밸리데이션 표시하기 — :invalid 대신 :user-invalid – 형우의 웹개발
  • Superset
  • Show HN: AboutIdeasNow – search /about, /ideas, /now pages of 7k+ personal sites | Hacker News
  • Why jalapeño peppers are less spicy (2023) | Hacker News
  • Peering through Lenovo’s transparent laptop into a sci-fi future - The Verge
  • Chartwell - Vectro
  • Why the Microsoft default font change from Calibri to Aptos upset some users | CNN
  • Tech Radio : 글로벌 1위 모바일 앱 PRISM Live Studio
  • Airfoil – Bartosz Ciechanowski
  • 애플, 전기차 개발 중단하고 팀을 생성형 AI로 전환 | GeekNews
  • random() distribution visualizer
  • ARIA Authoring Practices Guide | APG | WAI | W3C
  • The Era of 1-bit LLMs: ternary parameters for cost-effective computing | Hacker News
  • HTTP 리다이렉션과 메서드 변경 - 신현석(Hyeonseok Shin)
  • Where I'm at on the whole CSS-Tricks thing | Hacker News
  • The ‘Atlanta Magnet Man’ is saving our car tires, one bike ride at a time – WABE
  • Yes, YouTube has a new UI. Yes, it's terrible | Creative Bloq
  • 백악관, 개발자들에게 C와 C++를 피하고 '메모리 안전' 언어 사용 촉구 | GeekNews
  • ]]>
    <![CDATA[ 2024-02-26 주간 URL 모음 ]]> https://blog.update.sh/posts/weekly-urls-2024-02-26/ 65d405d25a1572000145f6a7 Mon, 26 Feb 2024 08:00:45 +0900
  • 접근성을 고려한 HTML 작성하기
  • Figma’s CEO on moving on after failed Adobe merger - The Verge
  • 프로세스 외부 의존성을 가진 데이터베이스는 무조건 목(Mock)으로 대체해야 하는가? - ohyecloudy’s pnotes
  • html.to.design | Convert any website into fully editable Figma designs
  • Maps Mania: AI Your Home on Street View
  • Bloom Filters
  • Turing Complete Origami | Hackaday
  • Microsoft가 MapLibre 스폰서십 프로그램에 참여 | GeekNews
  • 개발자 생산성을 측정할 때 저지르는 실수 | GeekNews
  • A former Gizmodo writer changed his name to ‘Slackbot’ and stayed undetected for months - The Verge
  • Hyeseong's Blog - 컨텐츠 압축을 위한 배경지식
  • ]]>
    <![CDATA[ 2024-02-19 주간 URL 모음 ]]> https://blog.update.sh/posts/weekly-urls-2024-02-19/ 65cac5cf5a1572000145f682 Mon, 19 Feb 2024 08:00:18 +0900
  • 2893: Sphere Tastiness - explain xkcd
  • Summary of Major Changes Between Python Versions
  • Built-in workaround for applications hiding under the MacBook Pro notch
  • 주커버그, 'Quest 3가 애플 비전 프로보다 더 좋은 제품임.' | GeekNews
  • Freenginx: 핵심 Nginx 개발자가 발표한 포크 | GeekNews
  • uv: Python packaging in Rust
  • OpenAI Sora: 텍스트에서 비디오를 생성하는 AI 모델 공개 | GeekNews
  • 데이터 앱을 위한 정적 사이트 생성기, Observable 2.0 | GeekNews
  • Open-Ko-LLM | 한국어 대규모 언어모델 리더보드
  • ]]>
    <![CDATA[ 2024-02-12 주간 URL 모음 ]]> = 2.28 · Issue #203375 · microsoft/vscode ]]> https://blog.update.sh/posts/weekly-urls-2024-02-12/ 65c0523d5a1572000145f63d Mon, 12 Feb 2024 08:00:35 +0900
  • My favourite Git commit
  • Polyreplay | Minesweeper
  • Introducing Pkl, a programming language for configuration
  • The Engineering behind Figma's Vector Networks
  • 매일 사용하는 브라우저 확장이 있으신가요? | GeekNews
  • 수학 유튜버 3blue1brown, 본인의 목소리를 학습한 AI를 이용해 시범적으로 한국어 | GeekNews
  • Workaround for machines that do not have glibc >= 2.28 · Issue #203375 · microsoft/vscode
  • leafac/kill-the-newsletter: Convert email newsletters into Atom feeds
  • 마우스 커서가 왜 약간 기울어져 있고 직선이 아닌가? | GeekNews
  • Rye: A Vision Continued | Armin Ronacher's Thoughts and Writings
  • jQuery v4.0.0 베타 공개 | GeekNews
  • Tetris Goes Full Circle | Hackaday
  • 2892: Banana Prices - explain xkcd
  • PAPERWALL: Chinese Websites Posing as Local News Outlets Target Global Audiences with Pro-Beijing Content - The Citizen Lab
  • Why It Was Almost Impossible to Make the Blue LED - YouTube
  • NumPy 2.0.0 Release Notes — NumPy v2.0.dev0 Manual
  • Comparing coroutines, by example, in Kotlin and Python | by Carmen Alvarez | Jan, 2024 | Medium
  • SQLALchemy vs Django ORM | Alexey Evseev
  • Annotating args and kwargs in Python | Redowan's Reflections
  • A Deep Dive Into Python's functools.wraps Decorator
  • Ten Python datetime pitfalls, and what libraries are (not) doing about it | Arie Bovenberg
  • Implement Parsers with Pylasu - Strumenta
  • (Almost) Every infrastructure decision I endorse or regret after 4 years running infrastructure at a startup · Jack's home on the web
  • ]]>
    <![CDATA[ 2024-02-05 주간 URL 모음 ]]> https://blog.update.sh/posts/weekly-urls-2024-02-05/ 65b7193d5a1572000145f611 Mon, 05 Feb 2024 08:00:19 +0900
  • Apple is bringing sideloading and alternate app stores to the iPhone
  • LottieFiles: Download Free lightweight animations for website & apps.
  • In Loving Memory of Square Checkbox
  • The Invention of a New Pasta Shape
  • GN⁺: 난파된 비행기 안에서 보잉 풋 옵션을 매입한 것이 내부자 거래일까?
  • ArVid: how Russians squeezed 4 hard drives into one VHS tape in the 90s
  • 미국 교수 '소금 한 꼬집'에 난리난 영국… '보스턴 차 사건'까지 소환
  • There's never going to be time
  • Roman Dodecahedrons: A Mystifying Archaeological Find
  • 페퍼노트
  • Adobe, Figma 인수 무산이후 웹-디자인 제품 개발 포기
  • GN⁺: 독일보다 큰 PDF 제작
  • Infinite Craft
  • ]]>
    <![CDATA[ 2024-01-29 주간 URL 모음 ]]> https://blog.update.sh/posts/weekly-urls-2024-01-29/ 65adc321fc6c3f0001a6d240 Mon, 29 Jan 2024 08:00:11 +0900
  • (번역) 웹 개발에 대해 엔지니어들이 믿는 이상한 것들
  • Please Don’t Make Me Use Another QR Code Restaurant Menu
  • 숫자 1은 올바른 JSON 형식인가?
  • Platform Tilt: Documenting the Uneven Playing Field for an Independent Browser Like Firefox
  • 모델을 재현할 수 없다면 그것은 오픈소스가 아니다
  • Conventional Commits
  • React, where are you going?
  • Have I Been Pwned adds 71 million emails from Naz.API stolen account list
  • Winlator - Wine을 통해 Windows 프로그램을 실행하는 Android 앱
  • Modder re-creates Game Boy Advance games using the audio from crash sounds
  • Caches: LRU v. random
  • Disney offers an elegant solution to VR’s movement problem
  • Celebrating our first 20,000 members
  • ServerFree Architecture
  • Zed is now open source
  • 포켓몬 컴퍼니, ‘팰월드’에 대한 공식 입장 표명
  • GN⁺: 샤오미 공기청정기의 DRM RFID칩 해킹하기
  • Hexcodle | The Daily Hexcode Gussing Game!
  • Coqui is shutting down
  • Use Compose Watch
  • ]]>
    <![CDATA[ 2024-01-22 주간 URL 모음 ]]> https://blog.update.sh/posts/weekly-urls-2024-01-22/ 65a4923c5c772200014c77ea Mon, 22 Jan 2024 08:00:13 +0900
  • Vue 3.4 발표
  • I am a Strange Dataset: Metalinguistic Tests for Language Models
  • Compressing Text into Images
  • 그누보드6 파이썬 버전으로 출시
  • Setting up Nix on macOS
  • Python Packaging, One Year Later: A Look Back at 2023 in Python Packaging
  • Show HN: I made a website to find best bus seat to avoid the sun while traveling
  • 128년만의 새 이름…전북도→'전북특별자치도' 공식 출범
  • '어디서 많이 본 “그 게임”을 막대 인간으로 진짜 만들어 봤는데, 과연 당신은 클리어할 수 있을까?' 한국어판 플레이 동영상
  • why lowercase letters save data
  • GN⁺: 후지쯔 버그로 무고한 사람들이 감옥에 간 것은 "처음부터" 알려져 있었다
  • ]]>
    <![CDATA[ 2024-01-15 주간 URL 모음 ]]> https://blog.update.sh/posts/weekly-urls-2024-01-15/ 659b86755c772200014c77b6 Mon, 15 Jan 2024 08:00:48 +0900
  • Editor.js
  • OROR Forge: Figma to Code 도구 제작기 (1) 디자인을 코드로 만들어보자!
  • 2023 JavaScript Rising Stars
  • GN⁺: 도커 이미지와 레이어 내용 탐색 도구 'Dive'
  • The curious case of the Raspberry Pi in the network closet
  • Android wifi says "Connected, no internet" but internet works just fine
  • Mobile ALOHA
  • Python 3.13 Gets a JIT
  • Show GN: 에어팟의 모션 센서로 올바른 자세를 추적하는 PosturePod
  • Upper Story
  • Turing Complete is a game about computer science
  • Twitch Plans Layoffs That Will Hit 35% of Staff
  • 물건 정리하는 쥐…라따뚜이가 실화?
  • CES 2024: The weirdest tech, gadgets and AI claims from Las Vegas
  • Top Front-End Tools Of 2023
  • Container2Wasm - 컨테이너를 WASM에서 실행할수 있게 변환해주는 도구
  • ]]>
    <![CDATA[ 2024-01-08 주간 URL 모음 ]]> https://blog.update.sh/posts/weekly-urls-2024-01-08/ 659382e95c772200014c7785 Mon, 08 Jan 2024 08:00:08 +0900
  • 절판품절 도서 구하는 법(국회도서관 우편 자료복사 서비스 이용하기)
  • 2023년에 잘 알려지지 않았던 66가지 긍정적인 뉴스 이야기
  • 임베딩(Embeddings)은 무엇이고 왜 중요한가
  • Pushing ChatGPT's Structured Data Support To Its Limits
  • LIERO official website
  • Email addresses are not good 'permanent' identifiers for accounts
  • 세계에서 가장 큰 ‘태양계 축소모델’
  • (번역) 당신은 고품질 소프트웨어를 구축하는 방법을 배운 적이 없습니다
  • What comes after open source? Bruce Perens is working on it
  • Real-world match/case
  • (웹툰) TCP형 인간 UDP형 인간
  • Beep Beep
    • Kagi 요약: Beeper는 안드로이드 사용자가 iMessage를 통해 아이폰 사용자에게 메시지를 보낼 수 있는 앱이었으나, Apple의 간섭으로 인해 어려움을 겪었습니다. Beeper는 일시적인 해결책을 찾았지만, 호환성을 유지하기 위해서는 예전에 탈옥된 아이폰이나 맥을 사용하는 등 복잡한 방법이 필요했습니다. 저자는 iMessage를 단순한 프로토콜이 아닌 Apple의 소유 서비스로 보아야 하며, Apple이 Beeper와 같은 앱의 무단 접근을 차단하는 것이 정당하다고 주장합니다. Apple이 iMessage에 대한 접근을 제한하여 사용자를 자사의 생태계에 묶는 것이 합법적인지, 이는 모바일 메시징 시장에서의 경쟁을 제한하는 것인지에 대한 논쟁이 제기되었습니다. 그러나 저자는 WhatsApp과 Signal과 같은 메시징 앱이 안전한 크로스 플랫폼 대안을 제공하며, Apple이 경쟁을 억압하고 있다는 주장에 의문을 제기합니다.
  • GN⁺: 저는 로우코드에 대해 회의적입니다
  • (번역) 자바스크립트의 await 사건의 지평선
  • Vue Patterns
  • PyPy, Git과 GitHub으로 이전 완료
  • Jony Ive, 아이폰 리드 디자이너를 데려와 OpenAI 하드웨어 개발에 참여 시키다
  • Python's soft keywords
  • Microsoft, Phi-2 언어모델의 라이센스를 MIT로 변경
  • ]]>
    <![CDATA[ 2024-01-01 주간 URL 모음 ]]> https://blog.update.sh/posts/weekly-urls-2024-01-01/ 658a49645c772200014c7768 Mon, 01 Jan 2024 08:00:57 +0900
  • Accessibility update: arXiv now offers papers in HTML format
    • HN: https://news.ycombinator.com/item?id=38724665
    • 기존 ar5iv에서 제공하던 HTML 보기 기능을 arxiv에서 바로 사용할 수 있도록 했습니다.
    • 번역기를 사용해서 읽기가 편해져서 좋습니다.
  • Beeper - Moving Forward
  • SMTP Smuggling - Spoofing E-Mails Worldwide
  • 썬더볼트와 USB4, 전송속도 및 호환성
  • How Big is YouTube?
  • [번역] 포맷팅 규칙이 ESLint에서 사라집니다
  • Three modern CSS properties your website must have
  • Icon Design Trends For 2024
  • ]]>
    <![CDATA[ 2023-12-25 주간 URL 모음 ]]> https://blog.update.sh/posts/weekly-urls-2023-12-23/ 657e9092714fed0001785272 Mon, 25 Dec 2023 08:00:40 +0900
  • Google 그룹스 유즈넷 지원 종료
    • HN: https://news.ycombinator.com/item?id=38649554
    • 해커뉴스 댓글에서는 유즈넷에 스팸이 줄어들어 오히려 좋다는 것 같습니다.
    • 이제 유즈넷은 진짜 역사의 뒤안길로 사라지고 있는 것 같습니다.
  • Database Fundamentals
  • SMERF: Streamable Memory Efficient Radiance Fields for Real-Time Large-Scene Exploration
    • HN: https://news.ycombinator.com/item?id=38632492
    • 잘 알지 못하는 분야지만 데모가 인상적입니다.
    • 현실적인 3D 공간을 브라우저에서 아주 높은 FPS로 렌더링할 수 있는 기술인가 봅니다.
  • Mixtral 8x7B, 인공지능도 협업이 대세!
    • 로컬에서 라이센스 걱정 없이 사용해볼만한 생성형 AI 모델이 공개된 것 같습니다.
    • 한국어 성능이 어떨지 궁금합니다.
  • Fine Tuning Mistral 7B on Magic the Gathering Drafts
  • 한국어 초거대 언어모델 리더보드
  • Bricked Xmas
  • The real research behind the wild rumors about OpenAI’s Q* project
    • OpenAI의 Q*에 대한 소문과 추측에 대해 설명하는 글입니다.
  • Announcing SvelteKit 2
    • SvelteKit 2.0이 릴리즈되었습니다.
    • 아직 Svelte를 써보진 않았지만, 기회가 되면 꼭 써보고 싶네요.
  • (번역) (더) 최신의 CSS Reset
    • CSS Reset에 어떤 규칙들이 적용되고 있는지 훑어보기 좋습니다.
  • 빈 리스트에 대한 all? 함수의 리턴 값은? - 공허참(vacuous truth)
  • 0% of the phrases of the original Wikipedia "Ship of Theseus" article remain
  • What Will Enter the Public Domain in 2024?
  • Figma and Adobe are abandoning our proposed merger
  • "I just bought a 2024 Chevy Tahoe for $1"
  • Vue.js와 D3.js를 사용하여 대시보드 만들기 Part1
    • 좀 더 자세한 설명이 있으면 더 좋았겠지만, D3로 차트를 만들 때 도움이 될 것 같습니다.
  • Beeper vs Apple battle intensifies: Lawmakers demand DOJ investigation
  • Tell HN: Microsoft.com added 192.168.1.1 to their DNS record
  • xkcd: Love Songs
    • 정말 소소한 주제에 대한 가벼운 시각화가 마음에 듭니다.
  • UP CLOSE AND PERSONAL WITH A MEMS MICROPHONE
  • 기준: 2023년
  • ]]>
    <![CDATA[ 레진코믹스 RSS로 구독하기 ]]> https://blog.update.sh/posts/lezhin-rss/ 657dcc81714fed0001785197 Fri, 17 Apr 2015 10:01:00 +0900

    더이상 레진코믹스 RSS를 서비스하지 않습니다.
    바쁜 사람들을 위한 한 줄 요약
    Lezhin Comics Feed(https://lezhin-rss.update.sh/)에서 구독하시면 됩니다.

    레진코믹스의 RSS를 제공하는 사이트를 만들었던 과정을 대략적으로 기록해 놓은 문서입니다.

    서론

    레진코믹스(http://www.lezhin.com/)라는 웹툰 사이트가 있습니다. 여러 작가들을 데려와서 유/무료 웹툰을 서비스하거나, 이미 출판된 만화도 가져와서 볼 수 있습니다.

    레진코믹스 메인 페이지
    (레진코믹스 메인페이지. 세월호 1주기가 스크린샷을 촬영한 날이었기에 로고에 노란 리본이 달려있습니다.)

    네이버나 다음과 같은 포털에서 운영하는 웹툰 서비스와 비슷하지만, 적극적인 유료화 정책과, 나름 고수위(?)의 성인 컨텐츠를 제공하는 게 특징입니다. 얼마 전에는 무슨 일이 있었는지 정확하게는 모르겠지만 레진코믹스 사이트를 방송통신위원회에서 차단하면서 이래저래 말이 많이 나오고 있습니다. 저는 그거랑은 별개로, 레진코믹스에서 연재중인 레바툰이 이런 저런 커뮤니티 사이트들에 공유되면서 관심을 갖게 됐습니다.

    저는 기본적으로 RSS 리더를 애용합니다. 주로 들어가는 블로그나 사이트 게시판 등등을 가능하면 RSS로 구독하여 받아보고 있습니다. 물론, 네이버나 다음 웹툰도 그렇게 하고 있습니다. 다음 웹툰 서비스는 자체적으로 RSS 구독이 가능하고, 네이버 웹툰은 링크(홍민희라는 분이 만드셨습니다. 파이썬 행사에서 뵌적이 있는것 같은 느낌이...) 에서 구독할 수 있습니다. 그러나 레진코믹스는 RSS 구독을 지원하지 않았고, 다른 사람이 만든 구독 사이트도 없는 것 같았습니다.

    Feed43(http://feed43.com/)과 같은 RSS 자동 생성 사이트를 이용할 수도 있었겠지만, 네이버 웹툰 구독 사이트처럼 한번 만들어 보기로 했습니다. 아마 시험기간이라 공부 말고 열심히 할 딴짓이 필요했던 것 같습니다.

    지원하리라 마음먹은 대략적인 기능은 아래와 같습니다.

    • 모든 구독은 RSS 2.0과 Atom 1.0을 복수 지원합니다.
      • 사실 별 차이점은 없지만, 그냥 둘 다 지원하기로 했습니다. 굳이 고르자면 Atom이 더 낫지만...
      • 레진코믹스의 API를 이용할 수 있다면 실시간 생성, 그렇지 않다면 매 시간마다 생성해서 캐시합니다
    • 개별 만화의 에피소드를 구독할 수 있습니다.
    • 새로 추가된 만화를 구독할 수 있습니다.
      • 왜냐면 새롭게 추가된 만화중에 보석같은 만화가 있을지도 모르니까요?
    • 구독할 수 있는 만화들을 보여주는 웹페이지를 만듭니다.
      • 해당 페이지에서는 만화의 이름이나 작가의 이름으로 검색이 가능해야 합니다.

    현재는 위의 기능을 모두 구현했습니다. 만들어진 구독 사이트는 Lezhin Comics Feed(http://kb.update.sh/lezhin-rss/)에서 볼 수 있습니다. 레진코믹스 API를 사용할 수는 없었으므로, 매 시간 정각에 구독정보를 업데이트 합니다.

    Lezhin Comics Feed 메인 페이지
    (Lezhin Comics Feed 메인 페이지)

    구현

    만들기로 마음을 먹은 김에 바로 작업에 들어갔습니다. 일단 웹사이트를 만들어야 하는데, 제가 다뤄본 웹 프레임워크는 Python Flask밖에 없어서 선택권이 딱히 없었습니다. 어차피 빠른 개발을 하려면 결국 Python을 선택하긴 했을 것 같습니다.

    만화 및 에피소드 정보 가져오기

    필요한 만화 및 에피소드 정보는 레진코믹스 웹사이트를 파싱해서 가져오면 될 것이라고 막연하게 생각했습니다. 그래서 레진코믹스 웹사이트를 켜서 이것 저것 봤는데... 분명히 동적으로 만화들을 처리하는데 ajax로 오고가는 데이터가 없었습니다.

    자세히 보니, 처음 웹사이트의 html을 가져올 때, inline javascript로 만화나 에피소드 정보를 다 넣어서 받아오고 있었습니다! 이게 문제인게, 원래는 HTML을 파싱하거나, ajax call을 분석해서 API를 따라 쓰려고 했는데 이것이 불가능하다는 뜻이었습니다.

    따라서, 적절하게 javascript를 파싱해서 만화 정보를 가져와야 했습니다. 우선은 requests 라이브러리를 이용하여 html을 가져와서, 이를 자체파싱(...)해서 사용했습니다. 이래저래 복잡하게 짤 수도 있겠지만, 딱히 퍼포먼스가 문제될 것 같지는 않았기에(물론 나중에 문제가 100% 생기겠지만) 제가 원하는 데이터의 시작 단어와 끝 단어를 기준으로 문자열을 잘라내어, json 처럼 취급했습니다.

    html의 inline javacript로 정보가 담겨 있다
    (html의 inline javacript로 정보가 담겨 있습니다)

    그래서 이래저래 고생하긴 했지만, 깔끔하게 json을 뽑아낼 수 있었습니다. 뽑아낸 만화 및 에피소드 정보는 자체 API를 만들어 아래와 같이 사용할 수 있게 했습니다.

    데이터 저장 및 업데이트

    얻어온 정보는 sqlite를 이용하여 저장해놓고 사용하기로 했습니다. 이는 Flask-SQLAlchemy를 통해 ORM으로 단순하게 해결했습니다. 만화와 에피소드에 맞는 모델만 적절하게 정의해놓으면 끝이었습니다.

    문제는 업데이트에 있었습니다. 그냥 반복문을 돌면서 전체 만화와 에피소드를 가져오는 것은 시간이 너무 오래 걸렸습니다. (이 당시 만화는 약 700개, 에피소드는 약 60,000화 이상이었습니다. 당연히 오래 걸립니다.) 전체 만화와 에피소드 목록을 가져오는데 약 13분이 소요되었습니다.

    대부분의 시간 소요는 네트워크 I/O 때문에 발생할 것이라 예측하고 multiprocessing을 이용해서 8 프로세스로 동작하게 했습니다. 결과는 만족스러웠습니다. 2분 정도만에 모든 만화와 에피소드 목록을 가져올 수 있었습니다.

    8 프로세스로 동작해서 약 2분만에 모든 만화와 에피소드 정보를 가져올 수 있습니다
    (8 프로세스로 동작해서 약 2분만에 모든 만화와 에피소드 정보를 가져올 수 있습니다)

    또, 레진코믹스의 웹 사이트 구조가 변경될 경우 업데이트가 정상적으로 이루어지지 않을 것입니다. 이 경우를 판단하기 위해 업데이트 중 파싱 에러가 발생할 경우 저에게 에러 정보를 gmail을 통해 보내도록 만들어 놓았습니다. 이젠 간단하게 cron에 매 시간 정각에 동작하도록 추가하면 끝입니다.

    구독정보 생성

    만화 및 에피소드 정보를 모두 가져왔으니, 이젠 이를 Atom과 RSS로 만들어서 제공해야 합니다. Atom 1.0의 경우 Flask는 Werkzeug를 통해 동작하므로, Werkzeug의 Atom Syndication 문서를 통해 구현하면 됩니다. RSS 2.0은 PyRSS2Gen을 통해 제공하기로 했습니다.

    Firefox로 열어본 Atom 구독정보
    (Firefox로 열어본 Atom 구독정보)

    메인페이지 제작

    사실 위의 작업보단 웹에서 구독할 수 있는 만화들을 보여주는 메인페이지 제작이 더 큰일이었습니다. 왜냐하면 제가 웹을 잘 못해서... 그래서 대충 대충 간단하게 끝냈습니다.

    우선 JQuery와 Bootstrap을 써서 간단하게 틀을 잡고, 제목대로 만화를 정렬해서 페이지당 50개씩 보여주기로 했습니다. 이 작업을 하면서 처음으로 Flask-SQLAlchemy에서 pagenate라는걸 사용할 수 있다는 것을 알았습니다. 여태까지 페이지 작업하는 코드를 일일히 짜줬는데, pagenate를 사용하면 간단하게 해결 할 수 있습니다.

    검색같은 경우에는 처음에는 Whoosh 사용을 고려했지만, 한글 설정이 미묘했고, 굳이 많지 않은 제목과 작가 검색에 검색 엔진까지 붙여 사용할 필요성을 느끼지 못해 사용하지 않았습니다.

    결론

    결과적으로 사이트는 간단하게 완성할 수 있었습니다. 처음 목표로 했던 기능은 모두 구현했으므로, 특별히 이상이 생기지 않는 한 더 이상 건드릴 일은 없을겁니다.

    본 프로젝트의 전체 소스코드는 https://github.com/rishubil/lezhin-rss 에서 확인할 수 있습니다. 만약 이 프로젝트를 클론해서 직접 실행해보고 싶다면, app/db 폴더를 생성하고, update.py 파일에서 mail 보내는 부분을 모두 지운 뒤, update.py를 실행시켜 db를 생성하고, debug.py 파일로 임시 웹서버를 실행해보면 됩니다.

    ]]>
    <![CDATA[ Yosemite에서 Synergy 직접 빌드하여 사용하기 ]]> https://blog.update.sh/posts/yosemite-synergy/ 657dd380714fed00017851ea Tue, 28 Oct 2014 20:47:00 +0900 멀티플랫폼간 마우스 및 키보드를 공유해주는 유명한 프로그램인 Synergy(http://synergy-project.org)가 어느새 유료화되었습니다. 다운로드 페이지로 가보면, 1인당 5달러를 결재하면 평생 사용할 수 있다... 라고는 합니다.

    하지만 원래 Synergy는 오픈소스 프로젝트 입니다. 그것도 GNU 라이센스가 적용되어 있는 프로젝트입니다. 이는 Synergy의 Github 페이지(https://github.com/synergy/synergy)로 가보면 확인할 수 있습니다. 따라서 그냥 Github에 공개된 코드를 직접 빌드하여 사용하기로 했습니다. 작업한 환경은 OS X 10.10 Yosemite입니다.

    http://synergy-project.org/wiki/Compiling 에 가보면 환경별 컴파일 방법이 간단하게 설명되어 있습니다. 따라서 저는 해당 내용을 따라서 Synergy를 컴파일해서 사용해 보기로 했습니다.

    일단 필요한 의존성 모듈을 설치해야 합니다. 저는 brew를 이용해서 cmake, qt를 설치했습니다.

    $ brew install cmake
    $ brew install qt
    

    의존성 모듈을 설치한 후에, 공식 문서에 나와있는 것과 같이 수행합니다.

    $ ./hm.sh conf -g1
    Mapping command: conf -> configure
    Running setup...
    Setup complete.
    Error: Arg missing: --mac-sdk <version>
    

    그럼 위와 같은 오류가 발생합니다. mac sdk 옵션이 없어서 발생하는 오류인 듯 싶어 옵션을 주어 실행해봤습니다.

    $ ./hm.sh conf -g1 --mac-sdk 10.10
    Mapping command: conf -> configure
    Error: Arg missing: --mac-identity <name>
    

    이번에는 mac identity 옵션이 없다고 합니다. 그럼 줘봅니다. 일단 test라고 주었습니다.

    $ ./hm.sh conf -g1 --mac-sdk 10.10 --mac-identity test
    Mapping command: conf -> configure
    cmake version 3.0.2
    
    CMake suite maintained and supported by Kitware (kitware.com/cmake).
    Creating dir: build/release
    Entering dir: build/release
    CMake command: cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release ../..
    -- The C compiler identification is AppleClang 6.0.0.6000054
    -- The CXX compiler identification is AppleClang 6.0.0.6000054
    (중간 생략)
    -- Looking for pthread_create in pthread
    -- Looking for pthread_create in pthread - found
    -- Found CURL: /usr/lib/libcurl.dylib (found version "7.37.1")
    -- OSX_TARGET_MAJOR=
    -- OSX_TARGET_MINOR=
    CMake Error at CMakeLists.txt:168 (message):
    Mac OS X target must be 10.x
    -- Configuring incomplete, errors occurred!
    See also "/Users/nesswit/Downloads/synergy-master/build/release/CMakeFiles/CMakeOutput.log".
    Going back to: /Users/nesswit/Downloads/synergy-master
    Error: CMake encountered error: 256
    

    색다른 오류가 저를 반겼습니다. 보아하니 OSX_TARGET_MAJOROSX_TARGET_MINOR 옵션이 적용이 되지 않은듯 합니다.

    이를 해결하기 위한 간단한 patch 파일을 작성했습니다. 자세한 내용은 아래와 같습니다.

    --- ./ext/toolchain/commands1.py	2014-10-27 15:53:52.000000000 +0900
    +++ ./ext/toolchain/commands1-new.py	2014-10-28 17:51:52.000000000 +0900
    @@ -451,15 +451,16 @@
     			cmake_args += ' -DCMAKE_BUILD_TYPE=' + target.capitalize()
     			
     		elif sys.platform == "darwin":
    -			macSdkMatch = re.match("(d+).(d+)", self.macSdk)
    -			if not macSdkMatch:
    -				raise Exception("unknown osx version: " + self.macSdk)
    -
     			sdkDir = self.getMacSdkDir()
     			cmake_args += " -DCMAKE_OSX_SYSROOT=" + sdkDir
     			cmake_args += " -DCMAKE_OSX_DEPLOYMENT_TARGET=" + self.macSdk
    -			cmake_args += " -DOSX_TARGET_MAJOR=" + macSdkMatch.group(1)
    -			cmake_args += " -DOSX_TARGET_MINOR=" + macSdkMatch.group(2)
    +
    +		macSdkMatch = re.match("(d+).(d+)", self.macSdk)
    +		if not macSdkMatch:
    +			raise Exception("unknown osx version: " + self.macSdk)
    +
    +		cmake_args += " -DOSX_TARGET_MAJOR=" + macSdkMatch.group(1)
    +		cmake_args += " -DOSX_TARGET_MINOR=" + macSdkMatch.group(2)
     		
     		# if not visual studio, use parent dir
     		sourceDir = generator.getSourceDir()
    @@ -485,10 +486,10 @@
     		if generator.cmakeName.find('Eclipse') != -1:
     			self.fixCmakeEclipseBug()
     
    -		# only on osx 10.9 mavericks.
    +		# only on osx 10.9 mavericks and 10.10 yosemite.
     		# manually change .xcodeproj to add code sign for
     		# synmacph project and specify its info.plist
    -		if self.macSdk == "10.9" and generator.cmakeName.find('Xcode') != -1:
    +		if (self.macSdk == "10.9" or self.macSdk == "10.10") and generator.cmakeName.find('Xcode') != -1:
     			self.fixXcodeProject(target)
     			
     		if err != 0:
    @@ -577,7 +578,8 @@
     		if os.path.exists(sdkPath):
     			return sdkPath
     
    -		return "/Developer/SDKs/" + sdkDirName + ".sdk"
    +		return os.popen('xcodebuild -version -sdk macosx' + self.macSdk + ' Path').read().strip()
    +		# return "/Developer/SDKs/" + sdkDirName + ".sdk"
     	
     	# http://tinyurl.com/cs2rxxb
     	def fixCmakeEclipseBug(self):
    

    해당 패치를 적용하고 실행한 결과는 아래와 같습니다.

    $ ./hm.sh conf -g1 --mac-sdk 10.10 --mac-identity test
    Mapping command: conf -> configure
    cmake version 3.0.2
    
    CMake suite maintained and supported by Kitware (kitware.com/cmake).
    Entering dir: build/release
    CMake command: cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DOSX_TARGET_MAJOR=10 -DOSX_TARGET_MINOR=10 ../..
    -- OSX_TARGET_MAJOR=10
    -- OSX_TARGET_MINOR=10
    -- Configuring done
    -- Generating done
    -- Build files have been written to: /Users/nesswit/Downloads/synergy-master/build/release
    Going back to: /Users/nesswit/Downloads/synergy-master
    QMake command: qmake gui.pro -r -spec macx-g++ "MACX_LIBS=-framework ApplicationServices -framework Security -framework cocoa -framework ServiceManagement" QMAKE_MACOSX_DEPLOYMENT_TARGET=10.10 QMAKE_MAC_SDK=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk
    Entering dir: src/gui
    Going back to: /Users/nesswit/Downloads/synergy-master
    

    생각대로 잘 동작합니다. 이대로 빌드를 진행합니다.

    $ ./hm.sh build
    Entering dir: build/release
    Scanning dependencies of target arch
    [ 0%] Building CXX object src/lib/arch/CMakeFiles/arch.dir/Arch.cpp.o
    (중간 생략)
    Log: Deploying plugins from "/usr/local/plugins"
    Log: Created configuration file: "Synergy.app/Contents/Resources/qt.conf"
    Log: This file sets the plugin search path to "Synergy.app/Contents/PlugIns"
    Going back to: /Users/nesswit/Downloads/synergy-master
    Error: [Errno 2] No such file or directory: '/Library/Frameworks/QtCore.framework/Contents/Info.plist'
    

    제가 설치한 qt는 brew로 설치했기 때문에 /Library/Frameworks/ 아래에 있지 않습니다. 따라서 해당 경로를 수정해야 합니다.

    이는 아까 패치파일을 적용한 ext/toolchain/commands1.py 파일의 826번째 줄 쯤에 있습니다. 해당 코드를 아래와 같이 수정합니다.

    			(qMajor, qMinor, qRev) = self.getQmakeVersion()
    			# if qMajor <= 4:
    			# 	frameworkRootDir = "/Library/Frameworks"
    			# else:
    			# 	# TODO: auto-detect, qt can now be installed anywhere.
    			# 	frameworkRootDir = "/Developer/Qt5.2.1/5.2.1/clang_64/lib"
    			frameworkRootDir = "/usr/local/Cellar/qt/4.8.6/Frameworks"
    

    이후, clean한 후 root 권한으로 다시 빌드해봅니다.

    $ ./hm.sh clean
    (생략)
    $ sudo ./hm.sh build
    Entering dir: build/release
    [ 0%] Building CXX object src/lib/arch/CMakeFiles/arch.dir/Arch.cpp.o
    (중간 생략)
    WARNING: Plugins = PlugIns
    Going back to: /Users/nesswit/Downloads/synergy-master
    

    경고... 가 뜨지만 더 이상은 그냥 무시하기로 했습니다.

    그럼, 정상적으로 생성된 Synergy.app 파일을 bin 폴더에서 확인할 수 있습니다.

    ]]>
    <![CDATA[ Windows 8의 바탕화면 우클릭 메뉴가 느리게 작동할 때 ]]> https://blog.update.sh/posts/slow-context-menu-on-windows-8/ 657dd64a714fed0001785207 Sun, 25 May 2014 03:27:00 +0900 Bootcamp로 사용하는 Windows 8.1의 바탕화면 우클릭 메뉴가 엄청나게 느리게 동작하기 시작했습니다. 관련 자료를 찾아보니 그래픽 카드 드라이버를 설치하면서 등록된 우클릭 메뉴 하나가 이상하게 동작하기 때문인 듯 했습니다.

    Windows 8과 Windows 8.1에서 발생하며, NVIDIA CPL Context Menu Extension(바탕화면에서 NVIDIA의 우클릭 메뉴)가 문제가 되는 경우가 대부분입니다.

    해결 방법은 다음과 같습니다.

    1. http://www.nirsoft.net/utils/shexview.html 에서 ShellExView를 다운받습니다.
    2. 다운받은 ShellExView를 우클릭하여 관리자 권한으로 실행합니다.
    3. 메뉴의 options에서 Filter by Extension Type의 Context Menu를 선택합니다.
      1. 혹시 NVIDIA CPL Context Menu Extension 란 항목이 있다면 해당 항목을 클릭하고 좌측 상단에 빨간 버튼을 눌러 중지시킵니다. (없다면 4번 항목으로)
      2. 메뉴의 options에서 Restart Explorer를 클릭합니다.
      3. 바탕화면에서 우클릭하여 문제가 해결되었는지 확인합니다. (해결되지 않았다면 4번 항목으로)
      4. 문제가 해결되었다면, NVIDIA의 우클릭 메뉴가 문제입니다. 딱히 사용하지 않아도 지장이 없다면 다음 절차를 진행할 필요는 없습니다.
    4. 리스트 중 분홍색 배경을 가진 항목들은 서드파티 프로그램에 의해 설치된 항목들입니다. 이 항목들을 모두 선택합니다. (ctrl 키를 누른 채로 클릭하면 여러 항목을 동시에 선택할 수 있습니다.)
    5. 좌측 상단의 빨간 버튼을 눌러 중지시킵니다.
    6. 메뉴의 options에서 Restart Explorer를 클릭합니다.
    7. 바탕화면에서 우클릭하여 문제가 해결되었는지 확인합니다. (해결되지 않았다면, 윈도우 기본 Shell extension에 의해 발생했거나 Shell extension에 의해 발생한 문제가 아닐 가능성이 있습니다.)
    8. 해결되었다면, 4~5번 항목에서 중지했던 항목들 중 하나만 다시 초록 버튼을 눌러 활성화시킵니다.
    9. 다시 문제가 발생할 때 까지 6-8번 항목을 반복합니다.
    10. 다시 문제가 발생하였다면 방금 다시 활성화시킨 그 항목이 원인입니다. 이름과 경로를 잘 보고 검색하여 문제를 해결하거나, 그냥 해당 extension을 비활성화시킨 채 사용합니다.

    출처: http://social.technet.microsoft.com/Forums/windows/en-US/5353106e-5b19-4a26-8446-72bedf40b169/rightclick-context-menu-in-desktop-appearing-slow-win-81?forum=w8itprogeneral

    ]]>
    <![CDATA[ Google에서 응용 프로그램 지정 암호를 얻어야 합니다. ]]> https://blog.update.sh/posts/google-app-password/ 657dd751714fed0001785221 Fri, 14 Feb 2014 00:03:00 +0900 OSX 10.9.1의 Mail client를 구글 계정을 이용하여 IMAP으로 동기화하려고 하니, 뜬금없이 "Google에서 응용 프로그램 지정 암호를 얻어야 합니다."라면서 계정 연동이 되지 않았습니다.

    한국어로 바로 검색해 보았으나 해결방법이 보이지 않아 영어로 검색하니 바로 해결되었습니다. 아래 링크를 참조하세요.

    https://support.google.com/mail/answer/1173270?hl=en

    혹 위 링크가 정상적으로 동작하지 않는다면, Authorizing applications & sites page 페이지로 이동하여 새로운 비밀번호를 생성한 후, 구글 계정 비밀번호 대신 생성된 비밀번호를 입력하여 계정 연동을 시도하면 됩니다.

    ]]>
    <![CDATA[ GB와 Gb의 차이점 ]]> https://blog.update.sh/posts/gigabyte-gigabit/ 657dd839714fed0001785233 Sun, 27 Feb 2011 18:43:00 +0900

    "20배 빠르다고?"…인텔 썬더볼트 뭐길래?
    http://www.zdnet.co.kr/news/news_view.asp?artice_id=20110224234635

    오늘, 우연히 2월 24일에 올라온 뉴스 기사를 보았습니다.
    신형 맥북프로에 탑재한 것으로 알려진 인텔의 새로운 데이터 전송 기술 '썬더볼트'에 관심이 집중되고 있다는 소식이었는데요, 거기서 조금 뭔가 걸리는 표현이 있었습니다.

    인텔은 당시 맥OS X를 탑재한 제품을 통해 라이트피크를 시연하며 기존 USB2.0보다 20배, > USB3.0보다 2배 빠른 초당 10기가비트(Gb) 전송 속도를 보인다고 설명해 주목받았다.

    라고 적혀있는 부분인데요,
    이 문장을 읽을 때, 별 생각없이 읽고 지나가다가는 이런 생각을 하기 쉽습니다.

    "아, 라이트피크는 초당 10GB의 데이터를 전송할 수 있구나! 엄청 빠르네"

    하지만, 자세히 보시면 그것과는 다릅니다.
    10기가바이트(GB)가 아닌 10기가비트(Gb)라는 것인데요,

    두 단위 사이의 관계는 다음과 같습니다.

    1 GB == 1 Giga Byte
    1 Gb == 1 Giga bit
    1 byte == 8 bit
    ---
    1 GB == 8 Gb
    

    따라서 초당 10기가비트(Gb)를 전송한다는 말은, 사실은 초당 1.25기가바이트(GB) 전송한다는 의미입니다.
    우리가 흔히 표기하는 인터넷 속도에 100Mbps 라는 표현이 있죠?
    이것도 마찬가지로 초당 최대 12.5MB까지 데이터를 전송할 수 있다는 의미가 됩니다.

    저번에 USB 3.0때도 마찬가지였죠, 최대 초당 5Gb까지의 전송 속도를 지원한다는 말은 사실 초당 625MB까지의 전송속도를 지원한다는 것과 같습니다.

    Gb와 GB는 엄연히 다른 단위이므로 혼동하지 않아야 하겠습니다.

    ]]>