<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mecanik1337</title>
    <description>The latest articles on DEV Community by Mecanik1337 (@mecanik).</description>
    <link>https://dev.to/mecanik</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1250743%2F66c81bf6-877e-4930-9003-91653fd2453e.png</url>
      <title>DEV Community: Mecanik1337</title>
      <link>https://dev.to/mecanik</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mecanik"/>
    <language>en</language>
    <item>
      <title>COBOL Database Migration Tool - VSAM, DB2, CICS, IMS to 5 Modern SQL Databases With DAL Code in 6 Languages</title>
      <dc:creator>Mecanik1337</dc:creator>
      <pubDate>Sun, 29 Mar 2026 06:15:34 +0000</pubDate>
      <link>https://dev.to/mecanik/cobol-database-migration-tool-vsam-db2-cics-ims-to-5-modern-sql-databases-with-dal-code-in-6-1omd</link>
      <guid>https://dev.to/mecanik/cobol-database-migration-tool-vsam-db2-cics-ims-to-5-modern-sql-databases-with-dal-code-in-6-1omd</guid>
      <description>&lt;p&gt;Good morning. &lt;/p&gt;

&lt;p&gt;This is my next addition to the COBOL world.&lt;/p&gt;

&lt;p&gt;A few weeks ago I posted about Easy COBOL Migrator, a desktop transpiler that converts COBOL to 6 modern languages. The most common question was: "What about the data layer?" Fair question. That's the part where migration projects actually stall and budgets explode. So I built the companion tool.&lt;/p&gt;

&lt;p&gt;Easy COBOL DB Migrator analyzes COBOL data definitions and generates modern database schemas, data access layer code, and migration scripts. Desktop app, runs offline, no cloud, no AI.&lt;/p&gt;

&lt;h3&gt;
  
  
  What it parses
&lt;/h3&gt;

&lt;p&gt;The tool detects 10 source system types automatically:&lt;/p&gt;

&lt;p&gt;Flat files (sequential and line-sequential) from FD record layouts. All 5 VSAM types: KSDS (indexed with RECORD KEY), ESDS (entry-sequenced), RRDS (relative with RELATIVE KEY), VRRDS (variable-length relative), LDS (linear). DB2 embedded SQL with EXEC SQL blocks, host variable resolution against WORKING-STORAGE, cursor detection, DECLARE CURSOR parsing. CICS file operations: READ, WRITE, REWRITE, DELETE, STARTBR, READNEXT mapped to database equivalents. IMS/DL-I with CALL 'CBLTDLI' and EXEC DLI, function codes (GU, GN, GNP, ISRT, REPL, DLET), PCB mask structures and qualified SSAs.&lt;/p&gt;

&lt;h3&gt;
  
  
  What it generates
&lt;/h3&gt;

&lt;p&gt;SQL DDL for PostgreSQL, MySQL, SQL Server, Oracle and SQLite with correct dialect. Each database gets proper auto-increment syntax (SERIAL vs AUTO_INCREMENT vs IDENTITY vs sequence), identifier quoting, type mappings and constraint definitions.&lt;/p&gt;

&lt;p&gt;Data access layer code in Java, C#, Python, C++, Rust and Go. Each language gets entity/model classes and repository/DAO classes with full CRUD (create, findById, findAll, update, delete). Java gets BigDecimal and JDBC PreparedStatement. C# gets decimal and ADO.NET. Python gets dataclass with Decimal and DB-API 2.0. C++ gets struct with std::optional and ODBC. Rust gets struct with derive macros and sqlx patterns. Go gets struct with db tags and database/sql.&lt;/p&gt;

&lt;p&gt;Migration/ETL scripts with database-specific bulk load commands: COPY for PostgreSQL, LOAD DATA for MySQL, BULK INSERT for SQL Server, SQL*Loader for Oracle, .import for SQLite. Plus validation queries for row counts and constraint verification.&lt;/p&gt;

&lt;p&gt;HTML migration report with field-level type mapping rationale, migration issues by severity, and access pattern documentation.&lt;/p&gt;

&lt;p&gt;CSV mapping exports and interactive ER diagrams exportable as PNG/SVG.&lt;/p&gt;

&lt;h3&gt;
  
  
  The type mapping engine
&lt;/h3&gt;

&lt;p&gt;Every PIC/USAGE combination maps correctly per database:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;PIC S9(7)V99 COMP-3&lt;/code&gt; becomes &lt;code&gt;NUMERIC(9,2)&lt;/code&gt; in PostgreSQL, &lt;code&gt;DECIMAL(9,2)&lt;/code&gt; in MySQL/SQL Server, &lt;code&gt;NUMBER(9,2)&lt;/code&gt; in Oracle.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;PIC X(30)&lt;/code&gt; becomes &lt;code&gt;VARCHAR(30)&lt;/code&gt;. Short alphanumerics (10 chars or less) use CHAR to preserve COBOL fixed-width semantics. Longer fields use VARCHAR.&lt;/p&gt;

&lt;p&gt;Level 88 conditions become CHECK constraints or BOOLEAN columns. Two values ("Y"/"N") generate BOOLEAN. Multiple enumerated values generate CHECK (or ENUM in MySQL).&lt;/p&gt;

&lt;p&gt;OCCURS arrays normalize to child tables with foreign keys and a seq_num column. FILLER fields are skipped. REDEFINES uses the primary definition and documents the alternative.&lt;/p&gt;

&lt;h3&gt;
  
  
  IMS hierarchy flattening
&lt;/h3&gt;

&lt;p&gt;IMS segments become relational tables with foreign keys:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;IMS:                          SQL:
POLICY (root)            -&amp;gt;   policy (PK: policy_key)
  +-- CLAIMANT           -&amp;gt;   claimant (FK -&amp;gt; policy)
  |     +-- CLAIM        -&amp;gt;   claim (FK -&amp;gt; claimant)
  |           +-- PAYMENT -&amp;gt;  payment (FK -&amp;gt; claim)
  +-- COVERAGE           -&amp;gt;   coverage (FK -&amp;gt; policy)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;DL/I function codes map to SQL: GU becomes SELECT WHERE, GN becomes cursor FETCH, ISRT becomes INSERT, REPL becomes UPDATE, DLET becomes DELETE.&lt;/p&gt;

&lt;h3&gt;
  
  
  Enterprise: actual data extraction
&lt;/h3&gt;

&lt;p&gt;The Enterprise edition reads real COBOL data files and handles EBCDIC-to-ASCII conversion (CP037), COMP-3 packed decimal unpacking, binary field parsing, zoned decimal sign handling, and implied decimal insertion. Exports as batched SQL INSERT statements or CSV.&lt;/p&gt;

&lt;h3&gt;
  
  
  How both tools work together
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Run Easy COBOL Migrator. Get converted code with TODO markers where EXEC SQL/CICS/DLI blocks were.&lt;/li&gt;
&lt;li&gt;Run Easy COBOL DB Migrator on the same source. Get database schema, data access code, and migration scripts.&lt;/li&gt;
&lt;li&gt;Replace the TODO markers with generated repository/DAO code.&lt;/li&gt;
&lt;li&gt;Run validation queries to verify data migration.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Free demo: PostgreSQL + C++, up to 3 source files.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://mecanik.dev/en/products/easy-cobol-db-migrator/#demo" rel="noopener noreferrer"&gt;Free demo download&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Desktop app, Qt/C++, Windows/macOS/Linux. Everything offline. This is how I spend my free time apparently.&lt;/p&gt;

&lt;p&gt;If you've got COBOL with VSAM files, DB2 queries or IMS databases, throw it at the demo. I want to know what breaks.&lt;/p&gt;

</description>
      <category>cobol</category>
      <category>database</category>
      <category>sql</category>
      <category>java</category>
    </item>
    <item>
      <title>I Built a Desktop COBOL Migration Tool That Converts to 6 Modern Languages</title>
      <dc:creator>Mecanik1337</dc:creator>
      <pubDate>Mon, 16 Mar 2026 07:23:24 +0000</pubDate>
      <link>https://dev.to/mecanik/i-built-a-desktop-cobol-migration-tool-that-converts-to-6-modern-languages-2337</link>
      <guid>https://dev.to/mecanik/i-built-a-desktop-cobol-migration-tool-that-converts-to-6-modern-languages-2337</guid>
      <description>&lt;p&gt;COBOL migration is the hottest topic in enterprise tech right now. Anthropic's Claude Code blog post knocked $40 billion off IBM's market cap in a single day. Banks are panicking about the "COBOL cliff" as 92% of COBOL developers approach retirement by 2030.&lt;/p&gt;

&lt;p&gt;I spent the last six months building a COBOL migration tool that takes a different approach from the AI-powered solutions making headlines. Easy COBOL Migrator is a desktop app that transpiles COBOL to C++ 17, Java 17, C# 12, Python 3, Rust and Go. It uses a full compiler pipeline, not an LLM. Everything runs offline. Your source code never leaves your machine.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why not use AI for COBOL migration?
&lt;/h3&gt;

&lt;p&gt;For a 200-line program, pasting COBOL into ChatGPT works fine. For a 200,000-line codebase with 300 shared copybooks and COMP-3 packed decimal arithmetic, AI-based COBOL migration breaks down for three reasons.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The output is non-deterministic.&lt;/strong&gt; Same COBOL in, different code out. Every time. Try reviewing or diffing that across a project with 500 files. A deterministic compiler gives you the same output for the same input, which means your migration results are auditable and reproducible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Decimal precision gets destroyed.&lt;/strong&gt; COBOL's &lt;code&gt;PIC 9(7)V99 COMP-3&lt;/code&gt; does exact fixed-point math using binary-coded decimal. LLMs routinely map this to &lt;code&gt;double&lt;/code&gt; or &lt;code&gt;float&lt;/code&gt;. That introduces rounding errors. A bank finding a 0.01 discrepancy in reconciliation doesn't file a bug report. They file a regulatory incident.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Copybook resolution doesn't exist.&lt;/strong&gt; Real COBOL codebases use &lt;code&gt;COPY ... REPLACING&lt;/code&gt; to share data definitions across hundreds of programs. The same copybook might be included 50 times with different substitutions. No LLM has a mechanism to resolve this across a whole project.&lt;/p&gt;

&lt;p&gt;AI is great for understanding COBOL. It's not reliable for converting it at scale with deterministic results.&lt;/p&gt;

&lt;h3&gt;
  
  
  How the COBOL migration pipeline works
&lt;/h3&gt;

&lt;p&gt;The architecture is a traditional multi-stage compiler:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;COBOL Source
  &amp;gt; COPY Preprocessor (resolves copybooks, applies REPLACING)
  &amp;gt; Lexer (220+ keywords, fixed/free format auto-detection)
  &amp;gt; Parser (recursive descent, 36 statement types, full AST)
  &amp;gt; Semantic Analyzer (symbol tables, type checking, scope validation)
  &amp;gt; Code Generator (one per target language)
  &amp;gt; Generated Source + Migration Report
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each stage is a separate C++ class. The parser builds a complete AST with expression trees, condition nodes and hierarchical data structures. The semantic analyzer validates everything before code generation starts.&lt;/p&gt;

&lt;h3&gt;
  
  
  The hardest parts of building a COBOL migration tool
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;PIC clauses are their own language.&lt;/strong&gt; &lt;code&gt;PIC S9(7)V99 COMP-3&lt;/code&gt; means signed, 7 integer digits, 2 decimal digits, stored as packed BCD. Mapping this correctly to &lt;code&gt;BigDecimal&lt;/code&gt; in Java, &lt;code&gt;decimal&lt;/code&gt; in C#, &lt;code&gt;decimal.Decimal&lt;/code&gt; in Python, &lt;code&gt;f64&lt;/code&gt; in Rust, &lt;code&gt;float64&lt;/code&gt; in Go and a custom &lt;code&gt;Decimal&lt;/code&gt; type in C++ took weeks of careful work. This is where most COBOL migration tools silently break.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PERFORM THRU is cursed.&lt;/strong&gt; &lt;code&gt;PERFORM PARA-A THRU PARA-C&lt;/code&gt; executes all paragraphs from A through C in source order, including whatever falls between them. It's implicit, position-dependent control flow with no equivalent in any modern language. I generate sequential paragraph calls, which is correct as long as paragraph order is preserved.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Level numbers create invisible nesting.&lt;/strong&gt; COBOL doesn't use braces or indentation for data structures. &lt;code&gt;01&lt;/code&gt; starts a record, then &lt;code&gt;05&lt;/code&gt;, &lt;code&gt;10&lt;/code&gt;, &lt;code&gt;15&lt;/code&gt; underneath are children based purely on numeric hierarchy. Miss this relationship and your struct generation produces flat fields instead of nested structures.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;EVALUATE TRUE is not a switch statement.&lt;/strong&gt; Each WHEN clause is an independent boolean condition, not a value comparison. I spent a week generating &lt;code&gt;switch&lt;/code&gt; statements before realizing the correct output is &lt;code&gt;if/else if&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fixed-format column rules are unforgiving.&lt;/strong&gt; Columns 1-6 are sequence numbers. Column 7 is an indicator (&lt;code&gt;*&lt;/code&gt; for comment, &lt;code&gt;-&lt;/code&gt; for continuation, &lt;code&gt;D&lt;/code&gt; for debug). Columns 8-72 are code. Columns 73-80 are identification that gets ignored. Accidentally reading column 73 as code corrupts your parse on every single line.&lt;/p&gt;

&lt;h3&gt;
  
  
  What the COBOL migration output looks like
&lt;/h3&gt;

&lt;p&gt;This COBOL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;       IDENTIFICATION DIVISION.
       PROGRAM-ID. PAYROLL-CALC.

       DATA DIVISION.
       WORKING-STORAGE SECTION.

       01  WS-EMPLOYEE.
           05  WS-NAME            PIC X(25).
           05  WS-HOURS           PIC 9(3)V99.
           05  WS-RATE            PIC 9(3)V99.
           05  WS-GROSS-PAY       PIC 9(5)V99.
           05  WS-TAX             PIC 9(5)V99.
           05  WS-NET-PAY         PIC 9(5)V99.

       01  WS-TAX-RATE            PIC V99 VALUE 0.20.
       01  WS-OVERTIME-MULT       PIC 9V9 VALUE 1.5.
       01  WS-OVERTIME-THRESHOLD  PIC 9(3) VALUE 40.
       01  WS-OVERTIME-HOURS      PIC 9(3)V99 VALUE 0.
       01  WS-REGULAR-HOURS       PIC 9(3)V99 VALUE 0.
       01  WS-COUNTER             PIC 9(2) VALUE 0.

       01  WS-PAY-GRADE           PIC 9 VALUE 0.
           88  JUNIOR             VALUE 1.
           88  SENIOR             VALUE 2.
           88  MANAGER            VALUE 3.

       PROCEDURE DIVISION.
       MAIN-PROGRAM.
           MOVE "Alice Johnson" TO WS-NAME
           MOVE 45.00 TO WS-HOURS
           MOVE 32.50 TO WS-RATE
           MOVE 2 TO WS-PAY-GRADE

           PERFORM CALCULATE-PAY
           PERFORM DISPLAY-PAYSLIP
           PERFORM DISPLAY-GRADE

           STOP RUN.

       CALCULATE-PAY.
           IF WS-HOURS &amp;gt; WS-OVERTIME-THRESHOLD
               COMPUTE WS-REGULAR-HOURS =
                   WS-OVERTIME-THRESHOLD
               SUBTRACT WS-OVERTIME-THRESHOLD FROM WS-HOURS
                   GIVING WS-OVERTIME-HOURS
               COMPUTE WS-GROSS-PAY =
                   (WS-REGULAR-HOURS * WS-RATE) +
                   (WS-OVERTIME-HOURS * WS-RATE *
                    WS-OVERTIME-MULT)
           ELSE
               COMPUTE WS-GROSS-PAY =
                   WS-HOURS * WS-RATE
           END-IF

           MULTIPLY WS-GROSS-PAY BY WS-TAX-RATE
               GIVING WS-TAX ROUNDED

           SUBTRACT WS-TAX FROM WS-GROSS-PAY
               GIVING WS-NET-PAY.

       DISPLAY-PAYSLIP.
           DISPLAY "================================"
           DISPLAY "  PAYROLL SUMMARY"
           DISPLAY "================================"
           DISPLAY "Employee:  " WS-NAME
           DISPLAY "Hours:     " WS-HOURS
           DISPLAY "Rate:      " WS-RATE
           DISPLAY "Gross Pay: " WS-GROSS-PAY
           DISPLAY "Tax (20%): " WS-TAX
           DISPLAY "Net Pay:   " WS-NET-PAY
           DISPLAY "================================".

       DISPLAY-GRADE.
           EVALUATE TRUE
               WHEN JUNIOR
                   DISPLAY "Grade: Junior"
               WHEN SENIOR
                   DISPLAY "Grade: Senior"
               WHEN MANAGER
                   DISPLAY "Grade: Manager"
               WHEN OTHER
                   DISPLAY "Grade: Unknown"
           END-EVALUATE.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Becomes this C++:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Transpiled from COBOL program: PAYROLL-CALC&lt;/span&gt;
&lt;span class="c1"&gt;// Generated by Easy COBOL Migrator on 2026-03-16 07:09:47&lt;/span&gt;

&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="n"&gt;include&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;iostream&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="n"&gt;include&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="n"&gt;include&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;cmath&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="n"&gt;include&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;cstdlib&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="n"&gt;include&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;cstdint&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="c1"&gt;// COBOL string move helper: truncate or right-pad to field width&lt;/span&gt;
&lt;span class="n"&gt;inline&lt;/span&gt; &lt;span class="nl"&gt;std:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;cobolMove&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nl"&gt;std:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;std:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;resize&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;' '&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// COBOL string comparison: pad shorter operand with spaces&lt;/span&gt;
&lt;span class="n"&gt;inline&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;cobolCmp&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nl"&gt;std:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nl"&gt;std:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nl"&gt;std:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="nl"&gt;std:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;la&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;la&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;resize&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;' '&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="n"&gt;lb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;resize&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;' '&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;la&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;compare&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lb&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main_program&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;calculate_pay&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;display_payslip&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;display_grade&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// WORKING-STORAGE variables&lt;/span&gt;
&lt;span class="n"&gt;struct&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;std:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;ws_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nl"&gt;std:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;' '&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;ws_hours&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;ws_rate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;ws_gross_pay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;ws_tax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;ws_net_pay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="n"&gt;ws_employee&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;ws_tax_rate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.20&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;ws_overtime_mult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;1.5&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;ws_overtime_threshold&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;ws_overtime_hours&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;ws_regular_hours&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;ws_counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;ws_pay_grade&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;inline&lt;/span&gt; &lt;span class="n"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;junior&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ws_pay_grade&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;inline&lt;/span&gt; &lt;span class="n"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;senior&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ws_pay_grade&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;inline&lt;/span&gt; &lt;span class="n"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;manager&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ws_pay_grade&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;int64_t&lt;/span&gt; &lt;span class="n"&gt;return_code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main_program&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ws_employee&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ws_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cobolMove&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Alice Johnson"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;ws_employee&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ws_hours&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;45.00&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;ws_employee&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ws_rate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;32.50&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;ws_pay_grade&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;calculate_pay&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;display_payslip&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;display_grade&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;calculate_pay&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ws_employee&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ws_hours&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ws_overtime_threshold&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;ws_regular_hours&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ws_overtime_threshold&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;ws_overtime_hours&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ws_employee&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ws_hours&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ws_overtime_threshold&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;ws_employee&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ws_gross_pay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="n"&gt;ws_regular_hours&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;ws_employee&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ws_rate&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="n"&gt;ws_overtime_hours&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;ws_employee&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ws_rate&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;ws_overtime_mult&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;ws_employee&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ws_gross_pay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ws_employee&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ws_hours&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;ws_employee&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ws_rate&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;ws_employee&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ws_tax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nl"&gt;std:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;round&lt;/span&gt;&lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="n"&gt;ws_employee&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ws_gross_pay&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;ws_tax_rate&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;100.0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mf"&gt;100.0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;ws_employee&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ws_net_pay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ws_employee&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ws_gross_pay&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ws_employee&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ws_tax&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;display_payslip&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;std:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"================================"&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nl"&gt;std:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;std:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"  PAYROLL SUMMARY"&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nl"&gt;std:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;std:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"================================"&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nl"&gt;std:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;std:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"Employee:  "&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;ws_employee&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ws_name&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nl"&gt;std:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;std:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"Hours:     "&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;ws_employee&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ws_hours&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nl"&gt;std:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;std:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"Rate:      "&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;ws_employee&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ws_rate&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nl"&gt;std:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;std:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"Gross Pay: "&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;ws_employee&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ws_gross_pay&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nl"&gt;std:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;std:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"Tax (20%): "&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;ws_employee&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ws_tax&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nl"&gt;std:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;std:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"Net Pay:   "&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;ws_employee&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ws_net_pay&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nl"&gt;std:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;std:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"================================"&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nl"&gt;std:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;display_grade&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;junior&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;std:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"Grade: Junior"&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nl"&gt;std:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;senior&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;std:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"Grade: Senior"&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nl"&gt;std:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;manager&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;std:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"Grade: Manager"&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nl"&gt;std:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;std:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"Grade: Unknown"&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nl"&gt;std:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;main_program&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which compiles and runs without even polishing it:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcywthwx0fsk7lwkdmwmc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcywthwx0fsk7lwkdmwmc.png" alt="Generated by Easy COBOL Migrator on 2026-03-16 07:09:47" width="800" height="251"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The migration report flags any constructs that need manual attention, like EXEC SQL blocks or dynamic CALL targets.&lt;/p&gt;

&lt;h3&gt;
  
  
  COBOL migration coverage
&lt;/h3&gt;

&lt;p&gt;The parser handles all four COBOL divisions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;36 statement types including MOVE, COMPUTE, IF/EVALUATE, all PERFORM variants including THRU and VARYING with AFTER, SORT/MERGE with key-field extraction, STRING/UNSTRING, INSPECT, SEARCH/SEARCH ALL, CALL with static and dynamic dispatch, GO TO DEPENDING ON, and RELEASE/RETURN for sort procedures&lt;/li&gt;
&lt;li&gt;Full data description with levels 01-88, OCCURS DEPENDING ON, REDEFINES, RENAMES, FILLER, all PIC/USAGE variants, and MOVE/ADD/SUBTRACT CORRESPONDING&lt;/li&gt;
&lt;li&gt;LINKAGE SECTION transpilation for subprogram interfaces with CALL BY REFERENCE, BY CONTENT and BY VALUE parameter passing&lt;/li&gt;
&lt;li&gt;File I/O with OPEN/CLOSE/READ/WRITE/REWRITE/DELETE/START, record packing/unpacking, seek-based in-place update and FILE STATUS tracking&lt;/li&gt;
&lt;li&gt;COPY preprocessor with nested copybooks up to 10 levels, REPLACING with pseudo-text substitution and circular-include detection&lt;/li&gt;
&lt;li&gt;40+ intrinsic functions mapped to native equivalents in all 6 languages&lt;/li&gt;
&lt;li&gt;EXEC SQL, EXEC CICS and EXEC DLI blocks preserved as comments with migration notes&lt;/li&gt;
&lt;li&gt;Built-in analysis tools: dead code detection, cross-reference maps, complexity metrics and COBOL source utilities&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Known limitations: indexed/relative file random/dynamic access converts to sequential with a migration note recommending database replacement. Report Writer and Screen Section are not supported.&lt;/p&gt;

&lt;h3&gt;
  
  
  Who needs a COBOL migration tool?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Migration consultants who want to accelerate their conversion projects&lt;/li&gt;
&lt;li&gt;Development teams at banks, insurers or government agencies migrating off mainframes&lt;/li&gt;
&lt;li&gt;Solo developers contracted for COBOL modernization work&lt;/li&gt;
&lt;li&gt;Anyone curious about what a 1959 programming language looks like as Rust&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Demo
&lt;/h3&gt;

&lt;p&gt;There's a free demo that converts single files up to 500 lines to C++ output.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://mecanik.dev/en/products/easy-cobol-migrator/" rel="noopener noreferrer"&gt;Product page&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If your organisation needs help with the parts the tool can't convert, like EXEC SQL replacement, database re-platforming or end-to-end migration, I also offer &lt;a href="https://mecanik.dev/en/services/" rel="noopener noreferrer"&gt;hands-on COBOL migration consulting&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;498 automated tests. 6 languages. One developer in London who now knows more about COBOL than he ever planned to.&lt;/p&gt;

&lt;p&gt;I'd love to hear what breaks. Drop your weirdest COBOL in the demo and let me know.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>showdev</category>
      <category>softwareengineering</category>
      <category>tooling</category>
    </item>
    <item>
      <title>I Built Free Desktop GUIs for Every Major Cloudflare Developer Service</title>
      <dc:creator>Mecanik1337</dc:creator>
      <pubDate>Fri, 13 Mar 2026 03:31:47 +0000</pubDate>
      <link>https://dev.to/mecanik/i-built-free-desktop-guis-for-every-major-cloudflare-developer-service-24hd</link>
      <guid>https://dev.to/mecanik/i-built-free-desktop-guis-for-every-major-cloudflare-developer-service-24hd</guid>
      <description>&lt;p&gt;If you've worked with Cloudflare's developer platform - D1, R2, KV, or Images, you know the drill: you're either writing CLI commands or jumping between tabs in a Cloudflare dashboard that wasn't really designed for heavy developer use.&lt;/p&gt;

&lt;p&gt;I got tired of it. So I built a suite of free desktop apps to fix that.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;Four cross-platform (Windows / macOS / Linux) Qt desktop apps, each targeting a different Cloudflare service:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;App&lt;/th&gt;
&lt;th&gt;Service&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Easy Cloudflare D1&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;D1 (serverless SQL)&lt;/td&gt;
&lt;td&gt;Browse, query, and manage your D1 databases with a full SQL editor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Easy Cloudflare R2&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;R2 (object storage)&lt;/td&gt;
&lt;td&gt;Upload, browse, and manage R2 buckets like an S3 browser&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Easy Cloudflare KV&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Workers KV&lt;/td&gt;
&lt;td&gt;Browse, create, edit, and monitor KV namespaces and key-value pairs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Easy Cloudflare Images&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Cloudflare Images&lt;/td&gt;
&lt;td&gt;Batch upload, variant preview, signed URL generation, bulk export&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;All four are completely free. No subscription, no SaaS, no telemetry.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Desktop and Not a Web App?
&lt;/h2&gt;

&lt;p&gt;A few reasons:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Security first.&lt;/strong&gt; Your Cloudflare API credentials never leave your machine. They're stored with strong local encryption (Windows DPAPI, macOS/Linux AES-256-GCM). No backend, no database of your tokens sitting somewhere you don't control. You can also &lt;strong&gt;restrict your API token by IP&lt;/strong&gt; in the Cloudflare dashboard so a leaked token becomes useless.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Native feel.&lt;/strong&gt; Browser-based tools for managing databases or object storage always feel slightly off. A native Qt app renders fast, handles large result sets well, and doesn't fight with your browser's tab limit.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Pain Points These Solve
&lt;/h2&gt;

&lt;h3&gt;
  
  
  D1
&lt;/h3&gt;

&lt;p&gt;Cloudflare's dashboard D1 editor is functional but limited, no query history, no result export, no multi-statement execution comfort. Easy Cloudflare D1 gives you a proper SQL editor with table browsing, so you can actually work with your data without reaching for &lt;code&gt;wrangler&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  R2
&lt;/h3&gt;

&lt;p&gt;If you've managed S3 before, you've probably used Cyberduck, S3 Browser, or similar tools. R2 had nothing comparable. Easy Cloudflare R2 fills that gap; drag and drop files, browse buckets, manage objects visually.&lt;/p&gt;

&lt;h3&gt;
  
  
  KV
&lt;/h3&gt;

&lt;p&gt;Workers KV is fantastic for edge config, feature flags, and caching; but inspecting what's actually stored is painful without a dedicated tool. Easy Cloudflare KV gives you a clean view of all your namespaces and lets you read, write, and delete keys without writing scripts.&lt;/p&gt;

&lt;h3&gt;
  
  
  Images
&lt;/h3&gt;

&lt;p&gt;The Cloudflare Images dashboard handles basic uploads, but batch workflows, variant previewing side-by-side, and generating signed URLs require either the API or a lot of copy-pasting. Easy Cloudflare Images makes all of that a few clicks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Technical Stack
&lt;/h2&gt;

&lt;p&gt;Built with C++ and Qt6, which gives native performance and a consistent experience across all three platforms from a single codebase. The binary is protected and closed-source, but the tools themselves are free to use.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Get Them
&lt;/h2&gt;

&lt;p&gt;Each app is available at &lt;a href="https://mecanik.dev/en/products/" rel="noopener noreferrer"&gt;mecanik.dev/products&lt;/a&gt;. You fill in a short form to get a free license key (3 activations per key) and download links for all platforms are emailed to you instantly.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://mecanik.dev/en/products/easy-cloudflare-d1/" rel="noopener noreferrer"&gt;Easy Cloudflare D1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mecanik.dev/en/products/easy-cloudflare-r2/" rel="noopener noreferrer"&gt;Easy Cloudflare R2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mecanik.dev/en/products/easy-cloudflare-kv/" rel="noopener noreferrer"&gt;Easy Cloudflare KV&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mecanik.dev/en/products/easy-cloudflare-images/" rel="noopener noreferrer"&gt;Easy Cloudflare Images&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Would love feedback from anyone already using Cloudflare's developer platform. What features would make these more useful for your workflow?&lt;/p&gt;

</description>
      <category>cloudflare</category>
      <category>devtools</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Build a Fast NLP Pipeline with Modern Text Tokenizer in C++</title>
      <dc:creator>Mecanik1337</dc:creator>
      <pubDate>Fri, 08 Aug 2025 09:14:58 +0000</pubDate>
      <link>https://dev.to/mecanik/build-a-fast-nlp-pipeline-with-modern-text-tokenizer-in-c-17b6</link>
      <guid>https://dev.to/mecanik/build-a-fast-nlp-pipeline-with-modern-text-tokenizer-in-c-17b6</guid>
      <description>&lt;p&gt;As a C++ developer in natural language processing (NLP) or machine learning (ML), you've probably hit the tokenization wall. &lt;/p&gt;

&lt;p&gt;Tokenization, more specifically splitting text into words, sub-words, or characters is critical for models like &lt;strong&gt;BERT&lt;/strong&gt; or &lt;strong&gt;DistilBERT&lt;/strong&gt;, but most C++ tokenizers are either slow, bloated with dependencies, or choke on Unicode.&lt;/p&gt;

&lt;p&gt;That's why I built &lt;strong&gt;Modern Text Tokenizer&lt;/strong&gt;, a header-only, UTF-8-aware C++ library that's fast, lightweight, and ready for ML pipelines.&lt;/p&gt;

&lt;p&gt;In this tutorial, I'll show you how to set up Modern Text Tokenizer, integrate it into your C++ project, and use it to preprocess text for NLP tasks. &lt;/p&gt;

&lt;p&gt;If you're building CLI tools, on-device NLP apps, or feeding data to transformer models, this tokenizer will save you time and headaches.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Modern Text Tokenizer?
&lt;/h2&gt;

&lt;p&gt;Modern Text Tokenizer is designed for developers who need performance and simplicity:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zero Dependencies&lt;/strong&gt;: No Boost or ICU, just a single header file.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UTF-8 Safe&lt;/strong&gt;: Handles emojis, multilingual text, and multibyte characters.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ML-Ready&lt;/strong&gt;: Maps tokens to vocabulary IDs for BERT, DistilBERT, and more.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fast&lt;/strong&gt;: Processes 174,000 characters in ~4.5 ms (36.97 MB/s throughput on Ryzen 9 5900X).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-Platform&lt;/strong&gt;: Tested on Ubuntu, Windows, and GitHub Actions CI.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Want to see it in action? Let's walk through setting it up and tokenizing text for an NLP pipeline.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up Modern Text Tokenizer
&lt;/h2&gt;

&lt;p&gt;Here's how to integrate it into your C++ project in minutes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Clone the Repo
&lt;/h3&gt;

&lt;p&gt;Grab the header file from the &lt;a href="https://github.com/Mecanik/Modern-Text-Tokenizer" rel="noopener noreferrer"&gt;&lt;strong&gt;Modern Text Tokenizer GitHub repository&lt;/strong&gt;&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/Mecanik/Modern-Text-Tokenizer.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy &lt;code&gt;Modern-Text-Tokenizer.hpp&lt;/code&gt; into your project directory.&lt;/p&gt;

&lt;h3&gt;
  
  
  Include the Header
&lt;/h3&gt;

&lt;p&gt;Add the header to your C++ code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;"Modern-Text-Tokenizer.hpp"&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Compile
&lt;/h3&gt;

&lt;p&gt;Ensure you're using C++17 or later and optimize for performance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;g++ &lt;span class="nt"&gt;-std&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;c++17 &lt;span class="nt"&gt;-O3&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; tokenizer_demo main.cpp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Download a Vocabulary
&lt;/h3&gt;

&lt;p&gt;For ML tasks, you'll need a vocabulary file (like from HuggingFace). For example, to use DistilBERT’s vocab:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-O&lt;/span&gt; https://huggingface.co/distilbert/distilbert-base-uncased/raw/main/vocab.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Tokenizing Text - A Quick Example
&lt;/h2&gt;

&lt;p&gt;Let's tokenize some text and encode it for an ML model. Here's a complete example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;"Modern-Text-Tokenizer.hpp"&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;TextTokenizer&lt;/span&gt; &lt;span class="n"&gt;tokenizer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Configure the tokenizer&lt;/span&gt;
    &lt;span class="n"&gt;tokenizer&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_lowercase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_split_on_punctuation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_keep_punctuation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Load a vocabulary (optional for ML pipelines)&lt;/span&gt;
    &lt;span class="n"&gt;tokenizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load_vocab&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"vocab.txt"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Encode text to token IDs&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Hello, world 👋 Let's build NLP apps."&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;ids&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tokenizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Print token IDs&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"Token IDs: "&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ids&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;" "&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Decode back to text&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;decoded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tokenizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ids&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"Decoded: "&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;decoded&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run this, and you'll see the token IDs and the decoded text. The tokenizer handles UTF-8 characters like emojis (&lt;code&gt;👋&lt;/code&gt;) without breaking a sweat.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance Benchmarks
&lt;/h2&gt;

&lt;p&gt;Modern Text Tokenizer is built for speed. Here's how it performs on a Ryzen 9 5900X with &lt;code&gt;-O3&lt;/code&gt; optimization, processing 174,000 characters:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Task&lt;/th&gt;
&lt;th&gt;Time (μs)&lt;/th&gt;
&lt;th&gt;Throughput&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Tokenization&lt;/td&gt;
&lt;td&gt;2159&lt;/td&gt;
&lt;td&gt;36.97 MB/s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Encoding&lt;/td&gt;
&lt;td&gt;1900&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Decoding&lt;/td&gt;
&lt;td&gt;430&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Total&lt;/td&gt;
&lt;td&gt;4489&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This makes it ideal for real-time NLP applications or large-scale text processing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Advanced Usage - Customizing for Your needs
&lt;/h2&gt;

&lt;p&gt;The fluent API lets you tailor the tokenizer to your project. For example, to tokenize without lowercase and keep punctuation as separate tokens:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;TextTokenizer&lt;/span&gt; &lt;span class="n"&gt;tokenizer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;tokenizer&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_lowercase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_split_on_punctuation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_keep_punctuation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;ids&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tokenizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello, World! C++ is awesome."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Need to preprocess for BERT? Load the vocab and add special tokens:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;tokenizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load_vocab&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"vocab.txt"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;ids&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tokenizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[CLS] Hello, world! [SEP]"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ensures compatibility with transformer models.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use Cases for C++ Developers
&lt;/h2&gt;

&lt;p&gt;Here are some practical scenarios where Modern Text Tokenizer shines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ML Preprocessing&lt;/strong&gt;: Prepare text for BERT or DistilBERT in C++ without Python.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CLI Tools&lt;/strong&gt;: Build fast text-processing utilities for data pipelines.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Embedded NLP&lt;/strong&gt;: Run tokenization on resource-constrained devices.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multilingual Apps&lt;/strong&gt;: Process text in any language with full UTF-8 support.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why Not Use Python?
&lt;/h2&gt;

&lt;p&gt;Python's tokenizers (like HuggingFace's &lt;code&gt;transformers&lt;/code&gt;) are great but come with overhead. If you're working in C++ for performance, portability, or embedded systems, Modern Text Tokenizer lets you stay in C++ without sacrificing functionality.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try It
&lt;/h2&gt;

&lt;p&gt;Ready to turbocharge your C++ NLP projects? Clone the &lt;a href="https://github.com/Mecanik/Modern-Text-Tokenizer" rel="noopener noreferrer"&gt;Modern Text Tokenizer repo&lt;/a&gt;, include the header, and start tokenizing. Got questions or cool use cases? Share them in the comments or open an issue on &lt;a href="https://github.com/Mecanik/Modern-Text-Tokenizer" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;For a deeper dive into its design and performance, check out my &lt;a href="https://mecanik.dev/en/posts/a-fast-utf-8-aware-c++-tokenizer-for-nlp-ml/" rel="noopener noreferrer"&gt;blog post&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let's make C++ NLP faster and easier!&lt;/p&gt;

</description>
      <category>cpp</category>
      <category>nlp</category>
      <category>machinelearning</category>
      <category>tokenization</category>
    </item>
    <item>
      <title>How to use efficiently IPSET with CSF Firewall</title>
      <dc:creator>Mecanik1337</dc:creator>
      <pubDate>Sat, 02 Mar 2024 09:30:36 +0000</pubDate>
      <link>https://dev.to/mecanik/how-to-use-efficiently-ipset-with-csf-firewall-5484</link>
      <guid>https://dev.to/mecanik/how-to-use-efficiently-ipset-with-csf-firewall-5484</guid>
      <description>&lt;p&gt;Hello,&lt;/p&gt;

&lt;p&gt;This is my first ever post here 😀&lt;/p&gt;

&lt;p&gt;In this post we will discuss how to use efficiently IPSET with CSF (ConfigServer Security &amp;amp; Firewall) Firewall. Unfortunately, I will not discuss what CSF is because it's not within the scope, but you can read about it &lt;a href="https://configserver.com/configserver-security-and-firewall/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you already used CSF or just getting started using it, you might have noticed that the &lt;code&gt;DENY_IP_LIMIT&lt;/code&gt; and &lt;code&gt;DENY_TEMP_IP_LIMIT&lt;/code&gt; is relatively small and fills up very fast. CSF advises you to use IPSET if you wish to increase this limit.&lt;/p&gt;

&lt;p&gt;What it doesn't tell you clearly is that even if you install IPSET and enable it inside CSF, &lt;strong&gt;you still need to increase&lt;/strong&gt; the values of &lt;code&gt;DENY_IP_LIMIT&lt;/code&gt; and &lt;code&gt;DENY_TEMP_IP_LIMIT&lt;/code&gt; otherwise it will have no effect. Trust me when I say that such a simple thing caused me quite some headaches...&lt;/p&gt;

&lt;h2&gt;
  
  
  What is IPSET?
&lt;/h2&gt;

&lt;p&gt;IPSET is a Linux kernel feature that allows for efficient management of large sets of IP addresses. It's particularly useful for implementing firewalls and access control lists. CSF leverages IPSET for managing IP addresses efficiently.&lt;/p&gt;

&lt;p&gt;Diagram:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;      +------------+
      |    IPSET   |
      +------------+
            |
    +-------|-------+
    |       |       |
+-------+ +-------+ +-------+
| IP    | | IP    | | IP    |
| Address| | Address| | Address|
+-------+ +-------+ +-------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;The "IPSET" box represents the IPSET data structure managed by CSF.&lt;/li&gt;
&lt;li&gt;Each IP address is stored within the IPSET, organized for efficient lookup.&lt;/li&gt;
&lt;li&gt;CSF interacts with IPSET to add, remove, or query IP addresses based on firewall rules and security policies.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How is IPSET configured in CSF?
&lt;/h2&gt;

&lt;p&gt;By default CSF provides you with following configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# The following sets the hashsize for ipset sets, which must be a power of 2.
#
# Note: Increasing this value will consume more memory for all sets
# Default: "1024"
LF_IPSET_HASHSIZE = "1024"

# The following sets the maxelem for ipset sets.
#
# Note: Increasing this value will consume more memory for all sets
# Default: "65536"
LF_IPSET_MAXELEM = "65536"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So what does this actually mean for you? The default settings for &lt;code&gt;LF_IPSET_HASHSIZE&lt;/code&gt; and &lt;code&gt;LF_IPSET_MAXELEM&lt;/code&gt; in CSF are set conservatively to balance memory usage and performance on a typical system. With this configuration the IPSET can accommodate up to 67,108,864 IP addresses (theoretically 😅).&lt;/p&gt;

&lt;p&gt;The configuration settings for &lt;code&gt;LF_IPSET_HASHSIZE&lt;/code&gt; and &lt;code&gt;LF_IPSET_MAXELEM&lt;/code&gt; affect the efficiency and capacity of the IPSET data structure within CSF. While it's true that the default configuration allows for a theoretical maximum of over 67 million IP addresses, it's essential to consider limitations such as memory usage and performance.&lt;/p&gt;

&lt;p&gt;Generally, increasing &lt;code&gt;LF_IPSET_MAXELEM&lt;/code&gt; will consume more memory as it allows for storing more IP addresses, while &lt;code&gt;LF_IPSET_HASHSIZE&lt;/code&gt; primarily affects lookup performance but also has some memory overhead.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Keep in mind:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A larger hash table requires more memory to store IP addresses efficiently. By defaulting to a smaller hash size (&lt;code&gt;LF_IPSET_HASHSIZE = "1024"&lt;/code&gt;), CSF ensures that it doesn't consume excessive memory resources on systems with limited RAM or where memory usage needs to be carefully managed.&lt;/li&gt;
&lt;li&gt;While a larger hash table can improve lookup performance for IP addresses, it may also introduce overhead in terms of memory access and CPU usage. By keeping the default hash size relatively small, CSF aims to strike a balance between memory consumption and performance impact on the system.&lt;/li&gt;
&lt;li&gt;The default settings are chosen to be compatible with a wide range of systems and use cases. They provide a reasonable starting point that works well for many installations without requiring fine-tuning.&lt;/li&gt;
&lt;li&gt;CSF is designed to be scalable, allowing administrators to adjust settings like &lt;code&gt;LF_IPSET_HASHSIZE&lt;/code&gt; and &lt;code&gt;LF_IPSET_MAXELEM&lt;/code&gt; based on their specific requirements and available resources. While the default settings may be conservative, they can be modified to better suit the needs of individual environments.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In summary, the default hash size in CSF is set to a relatively small value to strike a balance between memory usage and performance impact. Administrators can adjust these settings based on their specific requirements, system resources, and performance considerations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Increasing IPSET efficiently for performance
&lt;/h2&gt;

&lt;p&gt;In order to store millions of IP addresses efficiently you need to configure the limits accordingly, based on your available resources. As explained earlier, IPSET is mainly about RAM. So with that being said, I will provide example configurations for various amounts of RAM with balanced IP set settings.&lt;/p&gt;

&lt;p&gt;These configurations aim to strike a balance between memory usage, performance, and scalability. Keep in mind that these are example configurations, and you may need to adjust them based on your specific requirements and system characteristics.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;System with 2 GB RAM&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;LF_IPSET_MAXELEM = "65536&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;LF_IPSET_HASHSIZE = "131072&lt;/code&gt; (Approx. 131K IPs)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;System with 4 GB RAM&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;LF_IPSET_MAXELEM = "131072"&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;LF_IPSET_HASHSIZE = "262144"&lt;/code&gt; (~262K IPs)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;System with 6 GB RAM&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;LF_IPSET_MAXELEM = "196608"&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;LF_IPSET_HASHSIZE = "393216"&lt;/code&gt; (~393K IPs)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;System with 8 GB RAM&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;LF_IPSET_MAXELEM = "262144"&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;LF_IPSET_HASHSIZE = "524288&lt;/code&gt;" (~524K IPs)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;System with 16 GB RAM&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;LF_IPSET_MAXELEM = "524288"&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;LF_IPSET_HASHSIZE = "1048576"&lt;/code&gt; (~1M IPs)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;System with 32 GB RAM&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;LF_IPSET_MAXELEM = "1048576"&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;LF_IPSET_HASHSIZE = "2097152"&lt;/code&gt; (~2M IPs)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;System with 64 GB RAM&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;LF_IPSET_MAXELEM = "2097152"&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;LF_IPSET_HASHSIZE = " 4194304"&lt;/code&gt; (~4M IPs)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;System with 128 GB RAM&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;LF_IPSET_MAXELEM = "4194304"&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;LF_IPSET_HASHSIZE = "8388608"&lt;/code&gt; (~8M IPs)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Adjusting &lt;code&gt;LF_IPSET_HASHSIZE&lt;/code&gt; proportionally higher than &lt;code&gt;LF_IPSET_MAXELEM&lt;/code&gt; helps maintain efficient lookup times, especially as the number of stored IP addresses increases. These configurations aim to balance memory usage with performance requirements, allowing for optimal operation of CSF IP sets.&lt;/p&gt;

&lt;p&gt;You can monitor the current IPSET usage with the following command:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ipset list -t&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This command will list detailed information about the IP sets, including statistics such as the number of elements and the size of the hash table.&lt;/p&gt;

&lt;h2&gt;
  
  
  Potential overhead
&lt;/h2&gt;

&lt;p&gt;When increasing the limits for &lt;code&gt;LF_IPSET_HASHSIZE&lt;/code&gt; and &lt;code&gt;LF_IPSET_MAXELEM&lt;/code&gt; in CSF, there are several potential overheads to consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One of the most significant overheads is the increased memory usage. IPSET data structures consume memory, and larger hash tables or higher maximum element limits will require more RAM. This can impact overall system performance, especially on systems with limited memory resources.&lt;/li&gt;
&lt;li&gt;While larger hash tables can improve lookup performance by reducing collisions and improving cache locality, excessively large hash tables may lead to slower lookup times due to increased memory access overhead.&lt;/li&gt;
&lt;li&gt;Allocating more memory for IPSET may lead to resource contention with other processes running on the system. If the system is under heavy load, increased memory usage by IPSET could exacerbate resource contention issues.&lt;/li&gt;
&lt;li&gt;In extreme cases, allocating too much memory for IPSET could potentially lead to system instability, especially if the system runs out of physical memory and starts swapping excessively.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So please keep these in mind and don't start increasing the IPSET limits in CSF on small/budget type VPS.&lt;/p&gt;

&lt;p&gt;And that about concludes my first post here. Unfortunately I don't have more time right now to expand this article, but maybe in the coming weeks I will post more useful stuff about CSF 🙂&lt;/p&gt;

&lt;p&gt;PS: I really don't like the default editor here. It's too basic and quite bugged.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Until we meet again!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>linux</category>
      <category>firewall</category>
      <category>csf</category>
      <category>ipset</category>
    </item>
  </channel>
</rss>
