<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Adam on Medium]]></title>
        <description><![CDATA[Stories by Adam on Medium]]></description>
        <link>https://medium.com/@msradam?source=rss-20a23703cc5d------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*GiYiN5yJ8pa0xNQEpDJS7w.png</url>
            <title>Stories by Adam on Medium</title>
            <link>https://medium.com/@msradam?source=rss-20a23703cc5d------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Tue, 23 Jun 2026 15:39:29 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@msradam/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Big Iron under load: How to test IBM Z mainframes with k6]]></title>
            <link>https://medium.com/grafana-labs/big-iron-under-load-how-to-test-ibm-z-mainframes-with-k6-922a6a8ad8e3?source=rss-20a23703cc5d------2</link>
            <guid isPermaLink="false">https://medium.com/p/922a6a8ad8e3</guid>
            <category><![CDATA[mainframe]]></category>
            <category><![CDATA[ibm-z]]></category>
            <category><![CDATA[performance-testing]]></category>
            <category><![CDATA[k6]]></category>
            <category><![CDATA[load-testing]]></category>
            <dc:creator><![CDATA[Adam]]></dc:creator>
            <pubDate>Fri, 12 Jun 2026 13:39:36 GMT</pubDate>
            <atom:updated>2026-06-16T17:16:21.537Z</atom:updated>
            <content:encoded><![CDATA[<p><em>Far from being obsolete, IBM Z mainframes continue to power some of the most important workloads in the world. Here’s how I use k6 to ensure they perform well under peak load.</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*9RQunz5cHaJSqE5kQ-tEUw.png" /></figure><p><em>Note: The views expressed in this article are my own and do not necessarily reflect those of IBM.</em></p><p>“I’ve entered the mainframe.”</p><p>In movies, that’s usually the big moment in a hacking scene: our shades-and-trenchcoat-wearing hero has breached the villains’ systems and gained access to their secrets. It’s a line that’s become shorthand for high-tech intrigue.</p><p>But, for me, a mainframe is just part of my everyday work.</p><p>Despite their reputation as relics of a bygone era, mainframes remain some of the most important computers in the world. Mainframes process roughly <a href="https://www.ibm.com/think/insights/ai-on-the-mainframe">90% of credit card transactions</a> worldwide. The latest IBM model, the <a href="https://newsroom.ibm.com/z17">IBM z17</a>, handles up to 35 billion transactions per day. Seventy-one percent of the Fortune 500 run on mainframes; <a href="https://planetmainframe.com/2023/11/mainframes-by-the-numbers/">92 of the world’s top 100 banks</a> use IBM Z.</p><p>Scale like that changes the shape of failure. When a core banking platform stumbles under peak load, the consequences are not cinema: millions of customers locked out, payments delayed for weeks, regulators issuing fines in the tens of millions. The culprits are never really unexpected, either: untested changes or under-tested capacity. A tragedy of the commons, where the shared thing is trust and the bill comes due at peak load.</p><p>As a software test engineer on z/OS, that’s one of the most important parts of my job: know what the system handles before payday.</p><h3>Driving tests at the source</h3><p>IBM has long-standing load testing tools purpose-built for the platform: TPNS (Teleprocessing Network Simulator), first released in 1976, and its successor IBM Workload Simulator for z/OS (WSim). Both are deep platform tools, built for engineers who live on the system. As z/OS exposes more workloads through modern interfaces and development teams bring web-native workflows to the platform, there’s a case for a tool that meets them where they are.</p><p><a href="https://grafana.com/docs/k6/latest/">k6</a>, the open source load and performance testing tool, speaks that language: tests as code, version-controlled alongside the application, scripted in JavaScript, triggered from a CI pipeline, and results streaming to a Grafana dashboard. It’s the kind of tooling modern development teams already know how to operate.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*plI6VrSeDNIRr-m4f_3c4w.png" /></figure><p>k6’s Go engine stays lean under load: roughly 256 MB versus JMeter’s 760 MB in one <a href="https://blog.octoperf.com/open-source-load-testing-tools-comparative-study/">third-party comparative study</a>, enabling far higher concurrency per machine, though results vary by workload.</p><p>In banking, government, and regulated industries, mainframe environments are routinely air-gapped: no external network access and no reaching out to a package registry or a remote test runner. Every tool in the pipeline has to live on the platform itself, which means the load generator does too. On <a href="https://www.ibm.com/support/z-content-solutions/container-extensions/">zCX</a> (z/OS Container Extensions), k6 can run inside the mainframe’s own container runtime. Through the batch job scheduler, load tests become jobs that run alongside production workloads. The platform is modern. The tooling should be too.</p><p>One problem: k6 didn’t run on IBM Z’s s390x architecture. IBM Z has used s390x since the System/390 era; it’s a different instruction set entirely from the x86 chips in most developer laptops and cloud VMs, so building k6 natively on the platform wasn’t straightforward. IBM has been deliberately expanding the shell-first tooling story on z/OS: <a href="https://www.ibm.com/products/open-enterprise-foundation-zos">IBM Open Enterprise Foundation for z/OS</a> (OEF) ships Git, Bash, Curl, Vim, and more as a no-charge component of z/OS, and <a href="https://www.ibm.com/products/z-open-automation-utilities">Z Open Automation Utilities</a> (ZOAU) exposes z/OS facilities through UNIX-style commands and Python APIs. A z/OS developer should be able to type k6 run the same way they type curl, git, or bash.</p><h3>Go-ing Native</h3><p>IBM z/OS is not a UNIX OS, but it has a POSIX-compliant layer called z/OS UNIX System Services (USS), with SSH access, familiar tooling, and an alternative way of interacting with the mainframe’s resources beyond a green screen. IBM’s <a href="https://www.ibm.com/products/open-enterprise-sdk-go-zos">Open Enterprise SDK for Go</a>, generally available since January 2021, makes Go compilation native on z/OS: binaries that run directly on the hardware, no emulation, no containers.</p><p>I fork k6, clone it to my USS home directory, and kick off a go install. Two build errors, two fixes. First, afero (a filesystem abstraction library that k6 depends on) was missing z/OS in its list of supported platforms. In Go, build constraints are the mechanism that controls which platforms a file compiles for, and afero’s simply didn’t include zos:</p><pre>  <br>// Before    <br>//go:build aix darwin openbsd freebsd netbsd dragonfly    <br>         <br>// After    <br>//go:build aix darwin openbsd freebsd netbsd dragonfly zos  </pre><p>That fix was subsequently merged upstream (<a href="https://github.com/spf13/afero/pull/384">spf13/afero#384</a>).</p><p>Then ui_unix.go needed the same treatment: k6’s terminal progress bar redraw logic listed every supported Unix-like OS except z/OS. One more line:</p><pre>// Before   <br>//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd    <br>         <br>// After    <br>//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || zos  </pre><p>That fix was merged upstream too (<a href="https://github.com/grafana/k6/pull/2892">grafana/k6#2892</a>).</p><pre>❯ go install    <br>❯ $GOPATH/bin/k6    <br>         <br>             /\      |‾‾| /‾‾/   /‾‾/    <br>        /\  /  \     |  |/  /   /  /    <br>       /  \/    \    |     (   /   ‾‾\    <br>      /          \   |  |\  \ |  (‾)  |    <br>     / __________ \  |__| \__\ \_____/ .io    </pre><p>Two build tag additions. k6, now running natively on IBM Z.</p><p>k6 is now available in <a href="https://github.com/zopencommunity/k6port">zopen</a>, the community package manager for z/OS. I also provide prebuilt s390x binaries for IBM Z (including zLinux) on my personal fork of k6.</p><h3>I’d bank on it</h3><p>For the test target, I wanted something that looks like real production: COBOL programs, REST endpoints, and CICS (Customer Information Control System) transactions. CICS is IBM’s transaction processing middleware, the runtime that has handled the world’s core banking workloads for decades, sitting between the network and the underlying COBOL programs. IBM’s open source <a href="https://github.com/cicsdev/cics-banking-sample-application-cbsa">CICS Banking Sample Application (CBSA) </a>exposes a realistic set of banking operations through REST endpoints backed by actual COBOL programs, making it a faithful stand-in for a production core banking stack.</p><p>I based the transaction mix on the <a href="https://www.tpc.org/tpc_documents_current_versions/pdf/tpc-c_v5.11.0.pdf">TPC-C specification</a>, the industry-standard benchmark for database-heavy transactional workloads like banking: roughly 65% reads, 35% writes. Mapped to CBSA’s endpoints:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*glOBm0huVOXqONjDthwK7A.png" /></figure><p>Custom metrics separate read and write latency. One detail worth calling out: the IBM z/OS Connect endpoint returns 200 OK regardless of whether the underlying CICS transaction succeeded. The actual result lives in a field in the response body, so paySuccessRate checks the application-level outcome directly rather than relying on the HTTP status code.</p><pre> import { Rate, Trend, Counter } from &quot;k6/metrics&quot;;    <br>         <br> const inqDuration    = new Trend(&quot;cbsa_inq_duration_ms&quot;,  true);    <br> const payDuration    = new Trend(&quot;cbsa_pay_duration_ms&quot;,  true);    <br> const paySuccessRate = new Rate(&quot;cbsa_pay_success_rate&quot;);    <br> const txnTotal       = new Counter(&quot;cbsa_transactions_total&quot;);    <br> const readRate       = new Rate(&quot;cbsa_read_rate&quot;);    <br>         <br> export const options = {    <br>      vus: 10,    <br>      duration: &quot;10s&quot;,    <br>      thresholds: {    <br>        &quot;cbsa_inq_duration_ms&quot;:  [&quot;p(95)&lt;250&quot;],    <br>        &quot;cbsa_pay_duration_ms&quot;:  [&quot;p(95)&lt;350&quot;],    <br>        &quot;cbsa_pay_success_rate&quot;: [&quot;rate&gt;0.95&quot;],    <br>        &quot;http_req_failed&quot;:       [&quot;rate&lt;0.01&quot;],    <br>    },    <br>  };  </pre><h3>The numbers, Mason!</h3><p>A single k6 instance is <a href="https://grafana.com/docs/k6/latest/testing-guides/running-large-tests/">documented to generate up to 300,000 requests per second</a>. For context on what it’s hitting: a single LPAR (a logical partition, which is an isolated slice of mainframe capacity) has been measured in an <a href="https://www.redbooks.ibm.com/abstracts/redp5320.html">IBM Redbooks study</a> at up to 174,000 CICS transactions per second under benchmark conditions. Running k6 on the same hardware removes the network hop between generator and target, giving better latency accuracy and keeping the test inside the same operational boundary as the system under test.</p><h3>Let’s see it in action</h3><p>Here is k6 running natively on z/OS UNIX System Services, targeting CBSA’s IBM z/OS Connect endpoints: account inquiries, customer lookups, payment transactions, and live CICS backend:</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2F8orvNcKwNgM%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3D8orvNcKwNgM&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2F8orvNcKwNgM%2Fhqdefault.jpg&amp;type=text%2Fhtml&amp;schema=youtube" width="640" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/23cf8ca7d964172c604161a8fbe9447a/href">https://medium.com/media/23cf8ca7d964172c604161a8fbe9447a/href</a></iframe><p><em>The console output shows real-time transaction logs using the actual operation names from the underlying COBOL programs. The k6 summary table at the end breaks out the custom metrics alongside standard HTTP statistics.</em></p><p><em>Hostnames, endpoints, and identifiers have been obfuscated for security and compliance.</em></p><h3>Punchcards, protocols, and plugins</h3><p>k6’s--out influxdb and native Prometheus remote-write stream z/OS test metrics straight into a Grafana dashboard. With k6 as a native binary on z/OS, it slots naturally into the platform’s batch job system. On z/OS, Job Control Language (JCL) is the decades-old scripting format for submitting work to the batch scheduler, the same system that runs nightly reconciliation jobs and end-of-day processing for banks worldwide. Here’s a k6 load test submitted as a batch job via JCL:</p><pre>//K6LOAD   JOB (ACCT),&#39;K6 CBSA LOAD TEST&#39;,    <br>//             CLASS=A,MSGCLASS=X,NOTIFY=&amp;SYSUID    <br>//*-------------------------------------------------*    <br>//* Run k6 load test as a batch job                 *    <br>//*-------------------------------------------------*    <br>//STEP1    EXEC PGM=BPXBATCH    <br>//STDPARM  DD *    <br>  SH /home/user/go/bin/k6 run \    <br>     --vus 10 --duration 60s \    <br>     --out influxdb=http://grafana.internal:8086/k6 \    <br>     /home/user/banking_load_test.js    <br>/*    <br>//STDOUT   DD SYSOUT=*    <br>//STDERR   DD SYSOUT=*    </pre><p>The same 80-column syntax inherited from punchcards, now driving a load test that streams metrics to Grafana.</p><p>The longer play is k6 as a complete end-to-end test framework for z/OS. I wrote <a href="https://github.com/msradam/xk6-tn3270">xk6-tn3270</a> toward that end: a k6 extension that adds TN3270 emulation. TN3270 is the terminal protocol used to drive the text-based “green screen” interfaces that z/OS applications have exposed since the 1970s. It lets teams already familiar with the platform drive those workflows through the same scripting model they’d use for REST.</p><p>Add enough xk6 extensions and one tool covers REST, 3270, SSH, MQ, and so on. As of <a href="https://grafana.com/blog/k6-2-0-release/">k6 2.0</a>, the s390x port ships with the new k6 x mcp subcommand, which runs k6 as an MCP server so an AI agent can drive load tests directly.</p><p>If you want to try this yourself, <a href="https://github.com/cicsdev/cics-banking-sample-application-cbsa">CBSA</a> is on GitHub, <a href="https://www.ibm.com/community/z/zxplore/">ZXplore</a> covers the platform fundamentals for free, and k6 on z/OS is one zopen install k6 away.</p><p>There you have it: modern load testing, running natively on the platform that has powered global banking for over sixty years.</p><p>The hardware earned its reputation for resilience. k6 amplifies it.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=922a6a8ad8e3" width="1" height="1" alt=""><hr><p><a href="https://medium.com/grafana-labs/big-iron-under-load-how-to-test-ibm-z-mainframes-with-k6-922a6a8ad8e3">Big Iron under load: How to test IBM Z mainframes with k6</a> was originally published in <a href="https://medium.com/grafana-labs">Unprompted, by Grafana Labs</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Lean, Mean, ML-Powered Machine: Why Nintendo Switch 2 Ports Are Defying Expectations]]></title>
            <link>https://medium.com/@msradam/lean-mean-ai-powered-machine-why-nintendo-switch-2-ports-are-defying-expectations-538f4810ccbb?source=rss-20a23703cc5d------2</link>
            <guid isPermaLink="false">https://medium.com/p/538f4810ccbb</guid>
            <category><![CDATA[nintendo-switch-2]]></category>
            <category><![CDATA[gaming]]></category>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[technology]]></category>
            <category><![CDATA[nintendo]]></category>
            <dc:creator><![CDATA[Adam]]></dc:creator>
            <pubDate>Fri, 24 Oct 2025 19:01:10 GMT</pubDate>
            <atom:updated>2026-03-21T19:23:30.426Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*GvaPVXWU_zjAZ-ch.jpeg" /><figcaption>Star Wars Outlaws on Nintendo Switch 2 (Docked Mode) Source: Personal screenshot</figcaption></figure><p><em>This scene runs on 20 watts. A gaming PC draws 150–200+ watts just for the GPU. Switch 2’s entire system uses a fraction of that power.</em></p><p>Portable gaming has defined my relationship with the medium. The DS Lite sparked it in childhood. Today, my Switch and Steam Deck turn subway commutes into gaming sessions. There’s something magical about high-fidelity experiences that fit in a bag, and I’ll trade max settings for portability every time.</p><p>The Switch nailed the hybrid concept: seamless transitions between handheld and TV. My gaming PC sits at home pulling hundreds of watts. What fascinates me more is what engineers achieve within tight power budgets. Give me 10 watts and ingenuity over 200 watts of brute force.</p><p>Which explains why I’ve lurked in hardware speculation threads for years, parsing every leaked specification and blurry PCB photo. As a software developer with five years in the industry, I’ve watched these leaks through the lens of someone who codes for a living but nerds out over hardware constraints. Now the console exists, and I’m evaluating it through a new lens.</p><p>I’m now studying computer engineering in grad school, the classic geekdom to academia pipeline. The same day of my first Computer Architecture lecture, where my professor discussed domain-specific acceleration and thermal constraints, I got home and booted Star Wars Outlaws on Switch 2. Theory became sweet, sweet practice: Moore’s Law dead, energy efficiency paramount, specialized hardware compensating for modest clocks. The lecture posited it, Outlaws proved it.</p><p>T239’s efficiency isn’t luck, nor are its demonstrative games miracles. It’s deliberate architectural choices prioritizing watts-per-frame over raw teraflops. This article examines how those choices enable current-gen gaming in a portable form factor, acknowledging the challenges, caveats, and creativity.</p><p>This won’t exhaustively compare Switch 2 to Steam Deck or PS5. Architectural differences (ARM vs x86, console vs PC, Nvidia vs AMD) and developer experience confound direct comparisons. A $450, 1.4 cm tablet with 2020–2022 components won’t match PS5’s raw power. That’s not the point. The point is showing how architectural advantages deliver compelling experiences within thermal constraints that enable true portability.</p><h3>The Hardware</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*_L-yzn8vfmrCohqF.jpg" /><figcaption>The Switch 2’s unique, Ada-like GPU layout (Source: Geekerwan)</figcaption></figure><p>Switch 2 runs on Nvidia’s T239, built on Samsung’s 8N process — a hybrid of 10nm and 8nm technology confirmed by die analysis. Key specs:</p><ul><li><strong>GPU</strong>: 1536 CUDA cores, 1007 MHz docked / 561 MHz handheld</li><li><strong>CPU:</strong> 8 ARM Cortex-A78C cores, 1.0 GHz docked / 1.1 GHz handheld (6 cores for games)</li><li><strong>Memory:</strong> 12GB LPDDR5X at 102.4 GB/s (9GB for games)</li><li><strong>Power</strong>: ~20W docked / ~12W handheld</li></ul><p>The specs reflect modern mobile technology: LPDDR5X RAM and UFS 3.1 storage match current flagship phones, while microSD Express support (still uncommon in 2025) enables fast external storage. The GPU and CPU architectures are 2020s-era — Ampere-Ada hybrid and Cortex-A78C — balancing proven efficiency with features modern engines expect.</p><h4>Architectural Advantages</h4><p>T239 has features that aid it in punching above its weight, including but not limited to:</p><ul><li>12 Second-generation RT Cores for hardware ray tracing</li><li>48 Third-generation Tensor Cores for DLSS</li><li>Mesh shader support for efficient geometry processing</li><li>File Decompression Engine for hardware asset decompression</li></ul><p>Die analysis and observations from public Git repositories revealed optimizations beyond standard Ampere implementations. The chip includes first-level clock gating from Ada Lovelace, which powers down unused functional units at microsecond timescales — likely improving power efficiency significantly. The GPU layout has separated TPCs (texture processing clusters), which borrows from Ada rather than Ampere, demonstrating a forward-thinking, ‘hybrid’ approach to chip design. A pure Ada chip might have been more cutting-edge, but more expensive and with diminishing returns — while an Ampere chip with Ada features can keep costs down while retaining the same featureset as the current-gen consoles (both Ampere and RDNA2 are from 2020 and are DirectX12 Ultimate compliant).</p><p>This contrasts sharply with the original Switch’s stock Tegra X1 — a mobile GPU stretched thin by hybrid demands it wasn’t designed for. As Nvidia CEO Jensen Huang noted at launch: “This chip brings together three breakthroughs: the most advanced graphics ever in a mobile device, dedicated AI processors, and ultra low power operation.”</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*baVUKE_MLbZgePZe.jpeg" /><figcaption>The Switch 2 demonstrates remarkably power efficiency while running demanding games (Source: Digital Foundry)</figcaption></figure><h3>Power Efficiency: The Real Story</h3><p>Digital Foundry’s power analysis running Cyberpunk 2077’s benchmark reveals the efficiency advantage in concrete terms:</p><ul><li><strong>Switch 2 docked</strong>: 20–22W total system power</li><li><strong>Steam Deck OLED</strong>: 29–31W (same benchmark, matched settings)</li><li><strong>PlayStation 5 Slim</strong>: ~220W</li></ul><p>Switch 2 uses two-thirds the power of Steam Deck OLED while delivering superior docked performance. In handheld mode, Switch 2 draws ~9W while Steam Deck pulls 24–25W — one-third the power while maintaining competitive performance in optimized titles.</p><h4>The 8nm Question</h4><p>Samsung’s 8nm process sounds ancient compared to the 7nm TSMC node in Steam Deck, Series S, and other PC handhelds / current-gen consoles, raising reasonable questions about efficiency. But process node comparisons between Switch 2 and x86 handhelds miss a fundamental architectural difference: <strong>the combination of ARM CPU architecture and Nvidia’s Ada Lovelace GPU optimizations delivers superior efficiency</strong>.</p><p>ARM Cortex-A78C cores consume significantly less power per operation than x86 equivalents at similar performance levels — this is why smartphones and tablets universally use ARM. T239’s Ada Lovelace features like first-level clock gating (powering down unused units at microsecond timescales) and separated texture processing clusters further reduce power draw. Hardware-accelerated DLSS and RT further contribute to this by spreading out work between dedicated computational units, rather than pumping clocks into shader cores to force out a prettier image. Switch 2 achieves its efficiency through architecture rather than brute-force lithography. The 8nm node suffices because the underlying design is inherently power-conscious.</p><h4>The Bandwidth Question</h4><p>The 12GB LPDDR5X runs at 102.4 GB/s — modest compared to Xbox Series S’s 224 GB/s peak. That comparison ignores how the data actually moves. <strong>Effective bandwidth exceeds raw specifications</strong> thanks to specific architectural features:</p><p><strong>GPU compression: </strong>According to Nvidia’s GA102 (Ampere) whitepaper, delta color compression and lossless framebuffer compression have been shown to reduce memory traffic by 40–50% per frame on desktop implementations. While T239’s exact compression efficiency isn’t publicly documented, similar techniques should significantly reduce actual bandwidth required for rendering.</p><p><strong>File Decompression Engine: </strong>T239 includes hardware-accelerated FDE that unpacks LZ4 compressed files from game packages, offloading decompression work that would otherwise consume CPU cycles. Combined with UFS 3.1 storage, this makes asset loading faster and more power-efficient.</p><p>Raw bandwidth comparisons are misleading without accounting for compression advantages and efficient data pipelines built into the architecture.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*A9gPu9Qqhks6zyS5" /></figure><p>DLSS (Deep Learning Super Sampling) is T239’s <strong>most important </strong>feature. The technology uses AI to reconstruct high-resolution images from lower-resolution input, dramatically reducing GPU workload.</p><p>The math is simple: rendering at 720p instead of 1080p reduces pixel count by 44% : 44% fewer pixels to shade, texture, and light. Tensor Cores reconstruct missing detail using temporal data and neural networks, producing output approaching native quality.</p><p>Digital Foundry’s analysis revealed Switch 2 uses two distinct DLSS implementations:</p><p>- <strong>Standard CNN (Convolutional Neural Network) model</strong> (matching PC quality): Cyberpunk 2077, Street Fighter 6<br>- “<strong>Tiny DLSS</strong>” (~50% cheaper in frame time): Fast Fusion, Star Wars Outlaws</p><p>The lighter variant enables higher resolution targets impossible with standard DLSS given T239’s power budget. Fast Fusion achieves 4K/60fps by rendering at 648p using lighter DLSS. The trade-off: reduced reconstruction quality on moving objects, though static scenes remain sharp.</p><p>Even at aggressive upscaling ratios (540p → 720p in handheld mode), output remains clean in motion. DLSS represents domain-specific machine learning in action — AI purpose-built for rendering that aligns perfectly with Nintendo’s power-efficient design philosophy.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*UPwbIqZcCr0sMIFqeiGjPA.jpeg" /><figcaption>Resident Evil 9 on Nintendo Switch 2, utilizing the full DLSS CNN Model to reconstruct from 540p to 1080p with a 60 FPS target</figcaption></figure><h3>Cyberpunk 2077: Day-and-Date Parity</h3><p>Digital Foundry’s Cyberpunk analysis revealed impressive results for a launch title. Switch 2 targets 30fps at 1080p docked using custom settings blending high, medium, and low presets with bespoke solutions. Internal resolution fluctuates between 720p and 1080p depending on scene complexity, with DLSS reconstructing the final output.</p><p>CDPR’s approach reveals T239’s strengths. Rather than uniformly cutting quality, they developed custom solutions: bespoke shadow cascades, modified screen-space reflections, texture streaming rebuilt for UFS 3.1 storage and hardware decompression. The result: texture quality matching or exceeding Series S in several scenes despite lower memory bandwidth (Switch 2 does have 2 GB more total RAM than Series S).</p><p>Key findings:</p><ul><li>Texture quality matches/exceeds Xbox Series S in multiple scenes</li><li>Custom screen-space reflections and shadow cascades</li><li>Stable performance in most areas, mid-20s drops in dense Dogtown districts</li></ul><p>I put over 80 hours into Cyberpunk on Switch 2. The seamless transitions between handheld and docked modes — picking up a mission on the TV, continuing it on the Metro-North train, finishing it back home — exemplify the hybrid concept’s strength. Yes, it runs at 30fps with occasional drops. Yes, it’s rendering at lower resolutions than PS5. But the convenience of that portability, combined with DLSS maintaining image quality, made it my preferred way to experience Night City despite owning a gaming PC.</p><h4>The CPU Question</h4><p>The Phantom Liberty expansion’s Dogtown (dense crowds, complex AI) drops to mid-20s where Series S holds 30fps. Six ARM cores clocked at 1.1 GHz must be weak compared to the high-clocked x86 cores in PC handhelds and stationary home consoles, right?</p><p>Reality is more nuanced: developers need time adapting to ARM after years optimizing for x86. The original Switch’s Witcher 3 port demonstrated what aggressive CPU optimization achieves on ARM architecture — Saber Interactive eliminated busy-wait loops, moved cloth simulation to GPU (3–5x faster than CPU), leveraged ARM-specific features like shared L2 cache, and applied cache-friendly memory access patterns. The result: stable 30fps in a game that seemed impossible on Switch 1’s hardware.</p><p>Switch 2’s eight Cortex-A78C cores (six available to developers) offer significantly more headroom than Switch 1’s four cores (three available). Current-gen ports can achieve stable performance once developers adapt their optimization strategies to ARM architectures — it’s a learning curve, not an insurmountable barrier. And don’t forget the File Decompression Engine offloading work from the CPU!</p><p>The fact that Cyberpunk launched day-and-date with other platforms — handled in-house by CDPR rather than outsourced to port studios — demonstrates Nintendo’s improved third-party support compared to Switch 1’s late, reduced-quality ports.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Fp4IcZS472xB9Y2Kz3Mxyw.jpeg" /><figcaption>The RT Global Illumination putting in work (Docked Mode) Source: Personal screenshot</figcaption></figure><h3>Star Wars Outlaws: Ray Tracing on Battery Power</h3><p>Star Wars Outlaws represents, at least to me, a more impressive technical achievement than Cyberpunk: a current-gen-only game built entirely around hardware ray tracing, running on ~10W handheld / ~20W docked.</p><p>Outlaws runs at 30fps in both docked and handheld modes. Docked: 1080p output, DLSS upscaling from ~720p internal. Handheld:** 720p output, DLSS upscaling from ~540p internal. The 720p internal resolution in docked mode means the GPU renders 2.07 million pixels per frame — 44% fewer than native 1080p. DLSS reconstructs the missing detail using temporal data and AI inference. The game maintains a locked 30fps with occasional drops in dense areas like Toshara’s main city.</p><p>Digital Foundry’s analysis revealed impressive technical achievements. Switch 2 retains hardware ray tracing for diffuse global illumination and reflections — the same core rendering features present on PS5 and Series X, albeit at lower resolution with more noise in the lighting solution. Recent patches have improved texture quality and image stability.</p><p>More remarkably, performance proved superior to Series S in some scenarios. While both target 30fps, Series S exhibits frame pacing issues that make camera movement feel stuttery even when the frame counter shows 30fps. Switch 2 maintains consistent frame delivery — a locked 30fps feels smoother than an inconsistent 30fps. Digital Foundry concluded: “Performance is arguably worse on Microsoft’s junior console than on Nintendo’s hybrid.”</p><p>Despite Digital Foundry’s reservations about “Tiny DLSS,” I’ve found through 30+ hours with Outlaws that image quality holds up impressively both in stills and in motion, even on my 65-inch 4K television. The lighter DLSS implementation demonstrates remarkable stability for its performance cost.</p><p>The ray-traced bounce lighting captures Star Wars’ visual language — illuminated darkness, glowing panels in shadow. RT reflections run at lower resolution but integrate cohesively. Ubisoft maintained the game’s visual identity rather than compromising it for the platform.</p><p>Outlaws demonstrates what distinguishes Switch 2 from its predecessor: not just running current-gen games with cutbacks, but running current-gen rendering techniques. The game wasn’t designed to run without ray tracing — it’s the foundation of Snowdrop Engine’s lighting model. The fact that it runs at playable framerates on battery power represents the architectural advantage in action. This isn’t a downport — just a port. Switch 2 is a current-gen portable console.</p><p>It’s all in the architecture: the second-generation RT Cores in T239 are more efficient than Turing’s first-generation implementation. Nvidia’s GA102 architecture whitepaper notes 2x ray/triangle intersection performance compared to Turing, plus support for concurrent ray tracing and compute operations — keeping both RT Cores and shader cores active simultaneously rather than leaving units idle between passes.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*KIW-JmQvQ7kDlpr4.jpg" /><figcaption>Final Fantasy VII Remake Intergrade on Switch 2 (Docked Mode) (Source: Nintendo Life)</figcaption></figure><h3>Port Quality: Developer Commitment Matters</h3><p>Switch 2’s early library demonstrates a clear pattern: port quality tracks with developer investment and familiarity with the platform’s specialized features, not fundamental hardware limitations.</p><p><strong>Final Fantasy VII Remake Intergrade</strong> exemplifies thoughtful optimization. Digital Foundry called it “the best-looking thing I’ve seen on Switch 2 so far.” Director Naoki Hamaguchi confirmed the port uses PS5 lighting unchanged — “the crucial factor in terms of graphics quality” — while optimizing fog and post-processing for T239’s power constraints. The Switch 2 version retains PS5’s enhanced lighting model, improved textures, and volumetric fog implementations while running at 1080p/30fps docked. This isn’t a PS4 port scaled up, it’s a PS5 port scaled intelligently, preserving the visual elements that define the game’s cinematic presentation.</p><p><strong>Persona 3 Reload</strong> demonstrates the opposite conundrum. The game launched October 2025 at 30fps with significant framepacing issues that players described as “choppy” and “jarring,” despite maintaining a stable framerate. The port notably doesn’t utilize DLSS — Switch 2’s machine learning upscaling capabilities — which baffled reviewers given that CDPR, Ubisoft, and Square Enix successfully implemented DLSS in far more demanding titles. Reports suggest the resolution target remains 1080p in both modes despite the docked GPU boost, further indicating underutilization. Atlus explicitly stated they “prioritized delivering the Switch 2 version to everyone as quickly as possible” over optimization — a rush to market that DLSS implementation and proper framepacing could have addressed.</p><p>The variance in port quality reflects the platform’s learning curve and developer priorities, not impassable hardware constraints. Well-optimized Switch 2 ports aren’t ‘impossible ports’ or technical miracles — they’re simply ports. This represents a generational leap: Switch 2 is a current-gen portable console, not a last-gen device struggling with modern titles. Keep expectations in check as usual — not every developer has the time or resources to maximize hardware potential, and obviously, a portable drawing 20W can’t match a 220W home console.</p><p>But when studios invest the engineering resources (custom ARM optimization, DLSS integration, proper power management), Switch 2 delivers current-gen experiences at a fraction of the power consumption. That trade-off — maximum fidelity for portability — is precisely the point.</p><h3>What This Means Going Forward</h3><p>Five months into Switch 2’s lifecycle, developers are still learning the hardware. Early ports like Outlaws and day-one Cyberpunk show what’s possible with conservative targets. Future titles will push further as developers optimize for ARM CPUs and exploit T239’s architectural advantages.</p><p>More compute-intensive modern games may actually fare better on Switch 2 than lighter titles. Games designed around GPU compute shaders, hardware decompression, and AI upscaling naturally leverage Ampere’s strengths, while older engines built for different architectures may struggle without substantial porting work.</p><p><strong>Assassin’s Creed Shadows</strong> arrives December 2025 — a demanding current-gen open-world game targeting the platform just seven months post-launch, demonstrating developers are treating T239 as viable hardware for current-generation engines. <strong>Indiana Jones and the Great Circle </strong>(Spring 2026) is similarly RT-mandatory with no rasterized fallback, demonstrating confidence in T239’s RT cores and DLSS capabilities. <strong>Resident Evil Requiem</strong> (February 2026) is an incredible statement — the next mainline Resident Evil game, arriving day-and-date with the other console ports, using ray-traced global illumination with DLSS upscaling. Capcom’s director stated “even we were surprised when we first saw it, how beautifully it ran.”</p><p>First-party showcases will demonstrate what’s possible with full hardware knowledge and multi-year optimization cycles. The combination of Nvidia’s AI upscaling, efficient memory architecture, hardware-accelerated decompression, and custom power management creates a platform that delivers current-gen gaming experiences at a fraction of the power consumption.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*UCREq2jYrMy54Sm9.jpg" /><figcaption>Assassin’s Creed Shadows on Switch 2 (Source: Ubisoft Press Kit)</figcaption></figure><h3>At the End of the Day</h3><p>Switch 2 runs demanding titles at ~10W handheld / ~20W docked versus 150–200W on PC. That efficiency stems from architectural decisions: DLSS reconstruction, hardware ray tracing, unified memory with compression advantages, hardware decompression offloading CPU work, and purpose-built silicon designed around these features from day one.</p><p>Star Wars Outlaws, a current-gen game built entirely around hardware ray tracing, runs at playable framerates on battery power. That’s not a miracle port. It’s proof the architecture works as designed.</p><p>I carry this device in my messenger bag. It runs games designed for 200W GPUs. That gap exists because Nintendo built the entire system — silicon, APIs, developer tools — around DLSS, hardware decompression, and power efficiency from the start. Switch 2 fights battles on multiple fronts: thin and light with mass appeal, receiving current-gen ports at reasonable settings, while making a strong argument for its 450 USD price tag in spite of sticker shock. It’s accomplished all three. The console was designed WITH these features from day one — DLSS, RT cores, architectural optimizations — not as crutches to salvage weak specs. The best showings will be software leveraging all acceleration features. Beautiful results in the palm of your hand.</p><h3><strong>Sources</strong></h3><ul><li>Digital Foundry, “Switch 2 Hardware Review” (October 2025)</li><li>Digital Foundry, “Star Wars Outlaws Switch 2 Technical Analysis” (September 2025)</li><li>Digital Foundry, “Cyberpunk 2077 Switch 2 Tech Review” (June 2025)</li><li>Digital Foundry, “Nintendo Switch 2 DLSS Image Quality Analysis” (October 2025)</li><li>Digital Foundry, “Switch 2 vs Steam Deck Cyberpunk 2077 Benchmarked” (June 2025)</li><li>Digital Foundry, “Nintendo Switch 2: Final Tech Specs and System Reservations Confirmed” (May 2025)</li><li>Nvidia Corporation, “NVIDIA Ampere GA102 GPU Architecture Whitepaper” (2020)</li><li>Geekerwan, “This is Nintendo Switch 2’s CPU!” (June 2025)</li><li>Nintendo of America, “Creator’s Voice Special Edition — Nintendo Switch 2’s Custom Processor” (June 2025)</li><li>Roman Lebedev (Saber Interactive), “‘Witcher 3’ on the Nintendo Switch: CPU &amp; Memory Optimization” GDC Talk (2020)</li><li>Famiboards Thread, “Future Nintendo Hardware &amp; Technology Speculation and Discussion” (2022–2025)</li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=538f4810ccbb" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Ticks by Telnet: Load Testing IBM Z Mainframe Terminals with py3270 and Locust]]></title>
            <link>https://medium.com/theropod/ticks-by-telnet-load-testing-ibm-z-mainframe-terminals-with-py3270-and-locust-4da3a8dbe755?source=rss-20a23703cc5d------2</link>
            <guid isPermaLink="false">https://medium.com/p/4da3a8dbe755</guid>
            <category><![CDATA[load-testing]]></category>
            <category><![CDATA[open-source]]></category>
            <category><![CDATA[ibm]]></category>
            <category><![CDATA[python]]></category>
            <category><![CDATA[mainframe-modernization]]></category>
            <dc:creator><![CDATA[Adam]]></dc:creator>
            <pubDate>Thu, 13 Feb 2025 18:47:41 GMT</pubDate>
            <atom:updated>2025-04-20T20:47:17.556Z</atom:updated>
            <content:encoded><![CDATA[<p>🖥🖥🖥 At the stroke of a key, I have dozens of ASCII cows whispering sweet <em>moos</em>, load balanced amongst a population of virtual users, vying for their shared time on a mainframe terminal session. A hypnotic scenario, a server ‘farm’ with bit-tripped bovines chewing the cud on synthetic green screens, evoking The Matrix. But to what end?</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/640/0*_7Yffv6xr40pr3_r" /><figcaption>Screenshot from Control (2019)</figcaption></figure><p>Recall from our <a href="https://medium.com/theropod/swarming-stressed-servers-open-source-load-testing-on-z-os-mainframes-with-locust-42a1d5e3363e">previous adventure</a> the need to simulate a high volume of transactions on an IBM Z mainframe. As industry leading machines, these massive computers cannot buckle under the load of millions of concurrent requests and responses, and as mainframe testers it becomes our responsibility to simulate this type of workload to preemptively spot and zap out issues.</p><p>In my former tango with Locust, I deployed it for HTTP/S request testing, as it is well-suited out of the box to handle a hefty amount of concurrent GET, POST, PUT, and other such methods, submitted to an API endpoint. However, mainframes have several entrypoints to connect and execute functions on — besides HTTP/S, there are also web GUIs, FTP, SSH, and the classic Telnet protocol.</p><p>IBM 3270 is what is commonly known as the ‘green-screen’ terminal, and is the legacy interface for interacting with IBM mainframe software. Predominant z/OS applications such as Interactive System Productivity Display (ISPF) and System Display and Search Facility (SDSF) are only accessible through a 3270 emulator session connected via Telnet.</p><p>The following interface is of Telehack.com, a functional emulation of a classic green-screen interface that offers some toy applications, including cowsay .</p><pre>Connected to TELEHACK port 121<br><br>It is 10:03 pm on Sunday, February 9, 2025 in Mountain View, California, USA.<br>There are 119 local users. There are 26648 hosts on the network.<br><br>May the command line live forever.<br><br>Command, one of the following:<br>  2048         ?            a2           advent       aquarium     basic<br>  cal          calc         callsign     cat          ching        clear<br>  clock        date         delta        diff         eliza        factor<br>  figlet       file         fnord        head         help         ipaddr<br>  joke         liff         mac          md5          more         morse<br>  netstat      newuser      notes        octopus      pig          ping<br>  pong         primes       rainbow      rand         recover      rfc<br>  rig          roll         rot13        run          salvo        starwars<br>  sudoku       tail         today        typespeed    units        uptime<br>  users        uumap        uuplot       weather      when         zc<br><br>More commands available after login. Type HELP for a detailed command list.<br>Type NEWUSER to create an account. Press control-C to interrupt any command.<br>.</pre><p>The UI of a 3270 application lacks the graphical elements one might expect of a modern application, being built up of text and characters that are transmitted via a terminal, lines and blocks being formed from underlines, bars, and slashes. This has the advantage of producing lightweight programs that can still offer a ‘visual’ interface, and the learning curve is small for those already comfortable with keyboard based navigation. Instead of entering commands via a text buffer such as in an SSH session, input is accepted at certain coordinates within the display grid.</p><p>Thankfully, modern libraries exist that provide clean APIs for creating a 3270 session, one of which is `py3270`:</p><pre>from py3270 import Emulator<br>em = Emulator()<br><br>em.connect(&#39;3270host.example.com&#39;)<br>em.fill_field(17, 23, &#39;mylogin&#39;, 8)<br>em.fill_field(18, 23, &#39;mypass&#39;, 8)<br>em.send_enter()<br><br># if your host unlocks the keyboard before truly being ready you can use:<br>em.wait_for_field()<br><br># maybe look for a status message<br>if not em.string_found(1, 2, &#39;login successful&#39;):<br>    abort()<br><br># do something useful<br><br># disconnect from host and kill subprocess<br>em.terminate()</pre><p>Note how specific coordinates are provided to emulator functions such as `fill_field` and `string_found`, in order to make the most of 3270 automation, one must already have an understanding of the positioning of desired elements on the terminal.</p><p>Here’s some sample code to connect to telehack:</p><pre>em.connect(&#39;telehack.com&#39;)<br>em.wait_for_field()<br>em.send_string(&quot;cowsay&quot;)<br>em.wait_for_field()<br>em.send_string(&quot;cowsay hello&quot;)<br>em.save_screen(&quot;telehack.html&quot;)<br>em.terminate()</pre><p>Running this script and viewing the generated .HTML will reward us with:</p><pre>.cowsay hello<br> _______ <br>&lt; hello &gt;<br> ------- <br>        \   ^__^<br>         \  (oo)\_______<br>            (__)\       )\/\<br>                ||----w |<br>                ||     ||</pre><p>Note how the scripting for 3270 is ‘step-by-step’, with the user waiting for an input field and submitting commands one at a time. Those who are familiar with browser automation such as Selenium WebDriver may feel right at home, as this type of careful puppeteering is necessary when dealing with what is essentially a graphical user interface. I highly recommend manually performing tests to clearly identify the discrete instructions needed before diving into automation.</p><p>Now that we’ve established the ‘unit’ case, let’s return to the promise of Locust — commandeering a swarm of users to rampage on a server, slamming it with requests to emulate hectic real-world scenarios. But if Locust is primarily intended for HTTP/S testing, then where does the classic 3270 fit in?</p><p>A peek in the Locust documentation reveals that it “can be extended to test almost any system”, and indeed repositories like <a href="https://github.com/SvenskaSpel/locust-plugins">locust-plugins</a> host extensions that enable FTP, Selenium, Kafka, etc. load testing.</p><p>Since Telnet is just another connection protocol, and we have a handy Python interface to launch 3270 sessions, let’s dive right in and extend Locust. By following the lead of the given Locust plugins, we can write a wrapper around the base `User` and create hooks for the connection to be made:</p><pre>class tn3270User(User):<br>    abstract = True<br><br>    def __init__(self, environment):<br>        super().__init__(environment)<br>        self.client = tn3270Client(environment=environment)<br><br><br>class tn3270Client:<br>    def __init__(self, environment):<br>        self.environment = environment<br>        self.emulator = None<br><br>    def connect(self, user=None, password=None, port=23, timeout=30, trace=False, tracefile=None):<br>        self.user = user<br>        self.password = password<br>        self.port = port<br>        self.timeout = timeout<br>        self.tracefile = tracefile<br>        if trace:<br>            self.emulator = Emulator(visible=False, timeout=self.timeout, args=[&quot;-trace&quot;, &quot;-tracefile&quot;, self.tracefile])<br>        else:<br>            self.emulator = Emulator(visible=False, timeout=self.timeout)<br>        self.emulator.connect(&quot;y:%s:%d&quot; % (self.environment.host, self.port))</pre><p>This `tn3270Client` can now be cleanly evoked by a Locustfile:</p><pre>class DemoTn3270User(tn3270User):<br>    def on_start(self):<br>        self.environment.host = &quot;telehack.com&quot;<br>        self.client.connect()<br>        self.client.emulator.wait_for_field()<br>        self.client.string_wait(&quot;Type NEWUSER to create an account.&quot;)<br>        self.client.emulator.wait_for_field()<br>        self.client.emulator.send_string(&quot;cowsay&quot;)<br>        self.client.emulator.send_enter()<br><br>    @task<br>    def run_command(self):<br>        self.client.emulator.wait_for_field()<br>        self.client.emulator.send_string(&quot;cowsay hello&quot;)<br>        self.client.emulator.wait_for_field()<br>        # Pretty prints the current screen</pre><p>— and initiated from the command line as usual, e.g. locust -f locustfile.py -u 10 -t 60, which will launch the above script with 10 virutal users and run for 60 seconds. Upon start, each virtual user will instantiate their own 3270 emulator that connects to telehack.com and enters the `cowsay` program, and the repeated task that happens on each actor tick is the submission of `cowsay hello`. This results in 10 agents sending repeated requests to the machine that exercises the `cowsay` function. That’s a lot of cows.</p><p>This, of course, is a very rudimentary example. With the versatility and extensibility of scripting in Python, as well as Locust’s valuable features like distributed testing, there are numerous directions one could take this. On an actual IBM Z mainframe, one could use this as a template to script interactions with components such as DB2, CICS, RACF, and so on. Not just automating the behavior of one developer, but also the myriad of transactions that could occur on a typical enterprise system.</p><p>So long as modern developers continue to engineer extensions, green-screen interfaces will continue to live on. Even though software is moving towards more programmatic directions, such as via REST APIs, and more accessible UIs on a web browser, there is no denying how much infrastructure is sustained on applications that rely on 3270 interaction. These can still receive the care and attention they deserve without having to compromise on our desire for modernization.</p><p>Contrary to popular belief:</p><pre>```<br> ______________________________________________ <br>&lt; &quot;This dino can still learn some new tricks!&quot; &gt;<br> ---------------------------------------------- <br>\                             .       .<br> \                           / `.   .&#39; &quot;<br>  \                  .---.  &lt;    &gt; &lt;    &gt;  .---.<br>   \                 |    \  \ - ~ ~ - /  /    |<br>         _____          ..-~             ~-..-~<br>        |     |   \~~~\.&#39;                    `./~~~/<br>       ---------   \__/                        \__/<br>      .&#39;  O    \     /               /       \  &quot;<br>     (_____,    `._.&#39;               |         }  \/~~~/<br>      `----.          /       }     |        /    \__/<br>            `-.      |       /      |       /      `. ,~~|<br>                ~-.__|      /_ - ~ ^|      /- _      `..-&#39;<br>                     |     /        |     /     ~-.     `-. _  _  _<br>                     |_____|        |_____|         ~ - . _ _ _ _ _&gt;<br>```</pre><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=4da3a8dbe755" width="1" height="1" alt=""><hr><p><a href="https://medium.com/theropod/ticks-by-telnet-load-testing-ibm-z-mainframe-terminals-with-py3270-and-locust-4da3a8dbe755">Ticks by Telnet: Load Testing IBM Z Mainframe Terminals with py3270 and Locust</a> was originally published in <a href="https://medium.com/theropod">Theropod</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Open Zesame: Dual Development with Z Open Automation Utilities and z/OS Open Tools]]></title>
            <link>https://medium.com/theropod/open-zesame-dual-development-with-z-open-automation-utilities-and-z-os-open-tools-7c34f0482961?source=rss-20a23703cc5d------2</link>
            <guid isPermaLink="false">https://medium.com/p/7c34f0482961</guid>
            <category><![CDATA[open-source]]></category>
            <category><![CDATA[ansible]]></category>
            <category><![CDATA[unix]]></category>
            <category><![CDATA[ibm]]></category>
            <category><![CDATA[mainframe-modernization]]></category>
            <dc:creator><![CDATA[Adam]]></dc:creator>
            <pubDate>Mon, 26 Aug 2024 15:58:45 GMT</pubDate>
            <atom:updated>2024-08-26T17:35:13.250Z</atom:updated>
            <content:encoded><![CDATA[<p>🖥🖥 ‘Open’ can feel like a buzzword at times, eliciting <em>jamais vu, </em>feeling less and less like a meaningful descriptor and more like a noise prepended to software terminology to tickle shareholders. One only needs to look at the mainstream success of companies like ‘OpenAI’ and wonder — wait, what’s ‘open’ about it?</p><p>So lets take a step back, a deep breath, and look at two recent initiatives in the mainframe space that live up to the ‘open’ name — Z Open Automation Utilities and z/OS Open Tools. In specific, we’ll take a look at how the tooling offered by these projects can streamline development and testing on z/OS, making it easier for newer z/OS system programmers to tackle operations and automate their infrastructure.</p><p>Let’s jump right into a scenario: you’re a z/OS systems tester who wants to display the current status of OMVS to check on its health. The traditional method of issuing this command would be to open up a 3270 emulator i.e. a “green screen”, log onto a z/OS system via TSO, open SDSF, tab over to the command line and enter ‘D OMVS’, which will return the output. Oh — and this is what you’re working with:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/802/0*173WqwF8MemlDI7i.png" /></figure><p>A constrained window with a ‘graphical’ interface, with limited space for copy and pasting, and no immediate options to return parseable text formatted in JSON or YAML.</p><p>Interacting with the green screen is expected for most z/OS tasks. I highly advise system programmers to familiarize themselves with 3270 interfaces such as TSO, ISPF, and SDSF and how to navigate and operate with z/OS with it. They are highly reliable thanks to decades of development, are required for numerous mission critical tasks, and sustain a retro charm.</p><p>However, interacting <em>solely</em> via a “green screen” limits the extent with which one can integrate the capabilities of z/OS with modern automation and tooling. Languages like Python and CI/CD tools like Jenkins can work beautifully with z/OS — but it requires thinking outside of the beige box, and exploring more ‘open’ alternatives.</p><p>This is where Z Open Automation Utilities comes in, offering a suite of binaries that perform z/OS functions within z/OS Unix System Services — meaning they can be executed from an SSH session within your terminal emulator of choice. And to our luck — ZOAU ships with opercmd , which does as it says on the tin:</p><pre>ssh testuser@ABC<br>testuser@ABC &gt; opercmd &#39;D OMVS&#39;<br>testuser@ABC&amp;opercmd &#39;D OMVS&#39;<br>ABC        2026212  16:29:37.00             ISF031I CONSOLE TEST0000 ACTIVATED<br>ABC        2026212  16:29:37.00            -D OMVS<br>ABC        2026212  16:29:37.00             BPXO042I 16.29.37 DISPLAY OMVS 482<br>                                           OMVS     0012 ACTIVE             OMVS=(00)<br></pre><p>If the output is still a little unfriendly for one’s tastes, no matter, simply add the -j flag to spit it out in .json</p><pre>testuser@ABC &gt; opercmd -j &#39;D OMVS&#39;<br>{&quot;data&quot;:{&quot;output&quot;:&quot;BPXO042I 16.32.23 DISPLAY OMVS 617\nOMVS     0012 ACTIVE             OMVS=(00)\n&quot;},&quot;timestamp&quot;:&quot;2026212  16:32:23.00&quot;,&quot;timeout&quot;:100,&quot;command&quot;:&quot;D OMVS&quot;,&quot;program&quot;:&quot;opercmd&quot;,&quot;options&quot;:&quot;-j &quot;,&quot;rc&quot;:&quot;0&quot;}</pre><p>Excellent. Not only does this give us the output of the command, but it feeds back the return code, timestamp, and the original command we submitted — all packaged in neat JSON.</p><p>Now one can envision crafting more elaborate pieces of automation — perhaps a Python script that SSH’s into a mainframe, submits opercmdcommands to run health checks, parses the return output and prints them to a GitHub log, or a JavaScript server that continuously checks for DASD volume status and displays it on a webpage.</p><p>But with our capabilities boosted, why not dream bigger? Can we use bash for a more streamlined terminal experience? Execute curl to post the output of ZOAU commands to a web server? Pipe in jq to transform the json we’ve just received? But a quick search reveals these tools are either non-existent in a standard z/OS installation, or are scattered as convoluted installation packages from third parties.</p><p>Enter z/OS Open Tools: an initiative to port highly useful open-source tools to z/OS, primarily for use in z/OS Unix System Services. The above tools are all ported, alongside neovim , ncurses , nano , and more than 200 other programs.</p><p>A quick example of what can be done with jq , which is a command-line JSON processor:</p><pre>testuser@ABC&gt; opercmd -j &#39;D OMVS&#39; | jq<br>{<br>  &quot;data&quot;: {<br>    &quot;output&quot;: &quot;BPXO042I 16.51.59 DISPLAY OMVS 785\nOMVS     0012 ACTIVE             OMVS=(ST,R5,MM,Z2)\n&quot;<br>  },<br>  &quot;timestamp&quot;: &quot;2026212  16:51:59.00&quot;,<br>  &quot;timeout&quot;: 100,<br>  &quot;command&quot;: &quot;D OMVS&quot;,<br>  &quot;program&quot;: &quot;opercmd&quot;,<br>  &quot;options&quot;: &quot;-j &quot;,<br>  &quot;rc&quot;: &quot;0&quot;<br>}</pre><p>The | operator ‘pipes’ the output of opercmd <em>into </em>jq, so jq is reading the JSON that opercmd generates and is pretty-printing it for us. But jq is more powerful than simply rendering aesthetically pleasing text — for example, we can get a leaner output from the JSON and just retrieve the result of the operator command:</p><pre>testuser@ABC&gt; opercmd -j &#39;D OMVS&#39; | jq .data.output<br>&quot;BPXO042I 16.54.07 DISPLAY OMVS 845\nOMVS     0012 ACTIVE             OMVS=(AB,CD)\n&quot;</pre><p>Very clean.</p><p>Let us dive into a more complex example-what if I was embarking on a Pokedex project to catalog all the world’s portable creatures, and wished to record their traits in z/OS data sets — for I’m sure there are still mainframes in the fantasy world of Pokemon.</p><p>We can issue a curlGET request to <a href="https://pokeapi.co/">PokéAPI (pokeapi.co)</a> and pass in ‘Pikachu’ as our parameter, pipe that output into jq and pass in . to neatly retrieve the data, then write it to a flat text file titled pikachu_entry .</p><pre>curl --request GET --url https://pokeapi.co/api/v2/pokemon/pikachu | <br>jq . &gt;&gt; pikachu_entry</pre><p>We can quickly check that the new file pikachu_entry has captured the requested data by using head to get the first 10 lines of the file and wc to check the word count:</p><pre>testuser@ABC &gt; head -n 10 pikachu_entry<br>{<br>  &quot;abilities&quot;: [<br>    {<br>      &quot;ability&quot;: {<br>        &quot;name&quot;: &quot;static&quot;,<br>        &quot;url&quot;: &quot;https://pokeapi.co/api/v2/ability/9/&quot;<br>      },<br>      &quot;is_hidden&quot;: false,<br>      &quot;slot&quot;: 1<br>    }, <br><br>testuser@ABC &gt; wc -w pikachu_entry<br>  20477    pikachu_entry</pre><p>This looks good — however, we are in the realm of z/OS, so we’re not satisfied with just a flat text file- we’ve gotta wrangle with data sets. Let’s use the ZOAU decho command to write to a data set, without the need for using ISPF based editors:</p><pre>cat pikachu_entry | decho TESTUSER.PIKACHU.ENTRY</pre><p>decho accepts input from stdin , which means we can pipe in the output of cat pikachu_entry into decho and it will correctly parse it as input. This prevents us from needing to wrap the entirety of Pikachu’s entry between quotes — especially useful when dealing with large text content.</p><p>We can confirm that our data set was successfully created and filled in by logging into a TSO session, starting ISPF and querying for our data set name TESTUSER.PIKACHU.ENTRY — we should be able to browse it.</p><pre>  Menu  Options  View  Utilities  Compilers  Help                              <br>────────────────────────────────────────────────────────────────────────────── <br>DSLIST - Data Sets Matching TESTUSER.PIKACHU.ENTRY          Data Set - Browsed <br>                                                                               <br>Command - Enter &quot;/&quot; to select action                  Message           Volume <br>-------------------------------------------------------------------------------<br>         TESTUSER.PIKACHU.ENTRY                       Browsed           ABC123 <br>***************************** End of Data Set list ****************************<br>                                                                               <br>                                                                               <br>                                                                               <br>                                                                               <br>                                                                               <br>                                                                               <br>                                                                               <br>                                                                               <br>                                                                               <br>                                                                               <br>                                                                               <br>                                                                               <br>                                                                               <br>Command ===&gt;                                                  Scroll ===&gt; PAGE <br> F1=Help    F2=Split   F3=Exit    F5=Rfind   F7=Up      F8=Down    F9=Swap     <br>F10=Left   F11=Right  F12=Cancel                                               </pre><pre>   Menu  Utilities  Compilers  Help                                             <br> ───────────────────────────────────────────────────────────────────────────────<br> BROWSE    TESTUSER.PIKACHU.ENTRY                   Line 0000000000 Col 001 080 <br>********************************* Top of Data **********************************<br>{                                                                               <br>  &quot;abilities&quot;: [                                                                <br>    {                                                                           <br>      &quot;ability&quot;: {                                                              <br>        &quot;name&quot;: &quot;static&quot;,                                                       <br>        &quot;url&quot;: &quot;https://pokeapi.co/api/v2/ability/9/&quot;                           <br>      },                                                                        <br>      &quot;is_hidden&quot;: false,                                                       <br>      &quot;slot&quot;: 1                                                                 <br>    },                                                                          <br>    {                                                                           <br>      &quot;ability&quot;: {                                                              <br>        &quot;name&quot;: &quot;lightning-rod&quot;,                                                <br>        &quot;url&quot;: &quot;https://pokeapi.co/api/v2/ability/31/&quot;                          <br>      },                                                                        <br>      &quot;is_hidden&quot;: true,                                                        <br>      &quot;slot&quot;: 3                                                                 <br> Command ===&gt;                                                  Scroll ===&gt; PAGE <br>  F1=Help    F2=Split   F3=Exit    F5=Rfind   F7=Up      F8=Down    F9=Swap     <br> F10=Left   F11=Right  F12=Cancel</pre><p>Even with our convenient suite of ZOAU commands, it is reassuring to see the 3270 terminal reflect the new operations we’ve performed.</p><p>Now we have a z/OS sequential data set with information about Pikachu, that we are free to do with as we wish. With it being a z/OS data set, one can feed it into jobs that run z/OS programs like SORT and IDCAMS to manipulate and copy data. And with the data formatted as JSON, we can reliably parse it, for example:</p><pre>testuser@ABC&gt; dcat TESTUSER.PIKACHU.ENTRY | jq &#39;keys&#39;<br>[<br>  &quot;abilities&quot;,<br>  &quot;base_experience&quot;,<br>  &quot;cries&quot;,<br>  &quot;forms&quot;,<br>  &quot;game_indices&quot;,<br>  &quot;height&quot;,<br>  &quot;held_items&quot;,<br>  &quot;id&quot;,<br>  &quot;is_default&quot;,<br>  &quot;location_area_encounters&quot;,<br>  &quot;moves&quot;,<br>  &quot;name&quot;,<br>  &quot;order&quot;,<br>  &quot;past_abilities&quot;,<br>  &quot;past_types&quot;,<br>  &quot;species&quot;,<br>  &quot;sprites&quot;,<br>  &quot;stats&quot;,<br>  &quot;types&quot;,<br>  &quot;weight&quot;<br>]</pre><p>That’s right — we can feed the z/OS data set itself into jq . We now have all the keys in the Pikachu data model, so let’s pull some information from the abilities key:</p><pre>testuser@ABC&gt; dcat TESTUSER.PIKACHU.ENTRY | jq .abilities[].ability.name <br>&quot;static&quot;<br>&quot;lightning-rod&quot;</pre><p>The ZOAU command dcat will print the contents of the data set, then we use jq to filter that output by iterating over the abilities array and printing the name of each ability, which gives us a clean way of retrieving Pikachu’s innate gifts of Static and Lightning Rod.</p><p>jq gives us some powerful formatting tools, for example, we can dig into the stats key, pull out Pikachu’s numerical attributes, and format them as a table:</p><pre>testuser@ABC&gt; dcat TESTUSER.PIKACHU.ENTRY | jq -r &#39;.stats[] | &quot;\(.stat.name)\t\(.base_stat)&quot;&#39;<br>hp 35<br>attack 55<br>defense 40<br>special-attack 50<br>special-defense 50<br>speed 90</pre><p>Sometimes, we may want to be extra careful ensure the data is intact when copying it to a data set, as encoding issues may occur. We can create sequential data sets on the fly with dtouch -tseq TESTUSER.PIKACHU.STATS and edit it in ISPF:</p><pre>  File  Edit  Edit_Settings  Menu  Utilities  Compilers  Test  Help            <br>───────────────────────────────────────────────────────────────────────────────<br>EDIT       TESTUSER.PIKACHU.STATS                               Data set saved <br>****** ***************************** Top of Data ******************************<br>==MSG&gt; -Warning- The UNDO command is not available until you change            <br>==MSG&gt;           your edit profile using the command RECOVERY ON.              <br>000001 hp              35                                                      <br>000002 attack          55                                                      <br>000003 defense         40                                                      <br>000004 special-attack  50                                                      <br>000005 defense-defense 50                                                      <br>000006 speed           90                                                      <br>****** **************************** Bottom of Data ****************************<br>                                                                               <br>                                                                               <br>                                                                               <br>                                                                               <br>                                                                               <br>                                                                               <br>                                                                               <br>                                                                               <br>Command ===&gt;                                                  Scroll ===&gt; PAGE </pre><p>You may have noticed I’ve formatted the data in a particular way — this is to prepare it for z/OS’s SORT program! Let’s say we want to sort Pikachu’s stats from best to worst, we can now pass in this data set to SORT — and thanks to ZOAU, we will not need to submit a job. Instead, this can be handled all in one command line input:</p><pre>echo &quot;   SORT FIELDS=(17,2,ZD,D)&quot; | mvscmd --pgm=sort <br>                                           --sysout=* <br>                                           --sortin=TESTUSER.PIKACHU.STATS <br>                                           --sortout=TESTUSER.PIKACHU.STATS <br>                                           --sysin=stdin</pre><p>ZOAU’s mvscmd program allows us to run the usual programs one may invoke in JCL, but run via z/OS Unix System Services instead, allowing us to convert JCL syntax to single line runnable programs that will immediately provide output.</p><p>In this instance, we invoke the SORT program via pgm=sort , then pass in the IBMUSER.PIKACHU.STATS data set as both sortin and sortout data definition statements to indicate that we want to sort this particular data set ‘in-place’. We pass in “ SORT FIELDS=(17,2,ZD,D)” as the argument to SORT , specifying that the value we want to sort by (Pikachu’s statistic) starts on the 17th column, is 2 characters lone, is a zoned decimal (ZD), and presented in descending order.</p><p>After running this command in our Unix shell, we can retrieve the output of the modified data set, and verify that it has correctly sorted its stats from best to worst:</p><pre>testuser@ABC&gt; dcat TESTUSER.PIKACHU.STATS<br>speed           90<br>attack          55<br>defense-defense 50<br>special-attack  50<br>defense         40<br>hp              35</pre><p>To sum up — using binaries provided by Z Open Tools, we were able to pull data from a live API via curl and clean it up with jq . Then with the commands provided by ZOAU including decho, dtouch , and mvscmdare able to copy to and manipulate data sets to perform operations on this collected data — and we are capable of doing all of this within the comfortable confines of the Unix shell.</p><p>The proliferation of modernization efforts on z/OS have transformed it into a more open platform. ‘Open’, in this instance, is no buzzword.</p><p>Our capacity to execute tasks on z/OS has literally <em>opened</em> up, with fresh toolkits that integrate more beautifully and seamlessly with modern development environments and sensibilities. There has been an increased push for <em>open-source </em>on z/OS, with a vibrant community eager to share examples of how to leverage this new software to automate legacy tasks. And most important of all, we can approach development, testing, and maintenance of z/OS with more <em>open</em> minds that are receptive to new ways of interacting with these fascinating machines.</p><p>Let us continue this culture of openness, of community, and of progress.</p><p><em>Now go and be the very best, like no one ever was.</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/644/0*35_0DEVnhvWLZCcC.png" /><figcaption>Artist: Ken Sugimori</figcaption></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7c34f0482961" width="1" height="1" alt=""><hr><p><a href="https://medium.com/theropod/open-zesame-dual-development-with-z-open-automation-utilities-and-z-os-open-tools-7c34f0482961">Open Zesame: Dual Development with Z Open Automation Utilities and z/OS Open Tools</a> was originally published in <a href="https://medium.com/theropod">Theropod</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Go-ing Native: Porting Grafana k6 to z/OS with Go]]></title>
            <link>https://medium.com/theropod/go-ing-native-porting-grafana-k6-to-z-os-with-go-f7f73267c1c?source=rss-20a23703cc5d------2</link>
            <guid isPermaLink="false">https://medium.com/p/f7f73267c1c</guid>
            <category><![CDATA[mainframe]]></category>
            <category><![CDATA[load-testing]]></category>
            <category><![CDATA[grafana]]></category>
            <category><![CDATA[ibm]]></category>
            <category><![CDATA[k6]]></category>
            <dc:creator><![CDATA[Adam]]></dc:creator>
            <pubDate>Fri, 03 Mar 2023 17:02:34 GMT</pubDate>
            <atom:updated>2023-03-03T17:02:34.690Z</atom:updated>
            <content:encoded><![CDATA[<p>🖥🖥🖥 After a grueling night of ‘git’ clones and ‘go’ installs, I slammed the Enter key for the final time and witnessed as a flurry of user queries flooded the screen. The mainframe was handling everything — submitting, queuing, and processing each and every request — at breakneck speed. The tool that allowed for executing this blazing fast test wasn’t some internal, closed-source utility written in esoteric tongues. Rather, it was an open-source utility written in Go used by Cloud test teams around the world, now running natively on a z/OS mainframe.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*YrW6Xx7yEvQDifW8ytgHXg.png" /></figure><p>Let’s take a step back, and recall our motivation for load testing on mainframes from my <a href="https://medium.com/theropod/swarming-stressed-servers-open-source-load-testing-on-z-os-mainframes-with-locust-42a1d5e3363e">previous article</a>: we want to hammer our system with a simulated quantity of user activity so we can identify bugs and performance issues before they reach clients. To load test z/OS specifically, I deployed an API load test tool to send requests to a web server hosted on a mainframe, with each request instructing the system to execute some operation such as filesystem read-writes or batch processing. Let’s refer to the machine sending the requests as the ‘control’ node, and the machine processing requests as the ‘managed’ node. For example, a separate Linux instance is a control node submitting POST requests to a managed node in the form of a z/OS partition. The control node must have appropriate network and connection authorizations to communicate with our z/OS test system.</p><p>Out of multiple open-source load test tools, I opted for <a href="https://locust.io/">Locust</a> due to its ease of use and familiar Python syntax. This made scripting and executing tests more expedient and accessible, but it presented two downsides:</p><ol><li>Non-native: Locust does not run natively on z/OS. Even though z/OS supports Python and several of its libraries, Locust’s dependencies present low-level incompatibilities when dealing with how other Unix systems and z/OS Unix handle C calls — I know, as I’ve attempted to install Locust on z/OS and have only gotten so far.<br>This means that Locust must run and submit requests from a separate OS running on an external control node. This results in both the control and managed nodes being stressed — even if the intention is only to stress the managed node — and the control node has to be kept active for the duration of the test. This is rather inconvenient for those moments when I want to shut off my work laptop, or when I want to save resources and not leave a Linux VM running overnight.<br>While there may be a path to running Locust on z/OS natively, it may be more expedient to opt for a different tool with a higher chance of compatibility.</li><li>Performance: Locust is written in Python which is a high-level interpreted language. The Python interpreter will run through the script line-by-line as it executes it, as opposed to a compiled program which would be converted into machine code and therefore be more likely to perform faster. <br>Locust does offer distributed load generation features for scaling its tests, which could help accommodate the throughput of a mainframe. But this introduces more complexity when scripting these tests and selecting multiple control nodes — and as I say in point 1, it may be faster to just pick an alternative with better performance out-of-the-box.</li></ol><p>These two factors may impact one another. For example, a load test being executed on my work laptop may be bottlenecked by its CPU and memory, impacting the efficacy of the test since not all responses may be received in time to validate.</p><p>While Locust remains viable, I desired further optimization— a tool I could kick off on z/OS itself, and leave running 24/7. I wanted the mainframe to be both the control and managed node, handling all of the load. I also wanted it to be portable — a binary I could copy from partition to partition without recompiling or interpreting. One such tool fulfilled all of my requirements: <a href="https://k6.io/">Grafana k6</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*DUaN2HoyXCWbAN3Z.jpg" /></figure><p>Grafana k6 is the Go equivalent to Locust. It provides a command line interface with numerous options to parameterize testing, and parses test scenarios written in JavaScript to load test servers via API operations. It is written in Go, immediately solving the two issues presented above.</p><p>Well, almost. Go is indeed a compiled language known for its speed, and others have even measured <a href="https://binx.io/2021/06/12/i-used-python-for-a-load-test-and-look-what-happened-next/">direct comparisons</a> between k6 and Locust, favoring the former. Native z/OS compatibility, on the other hand, is not a given. While <a href="https://www.ibm.com/products/open-enterprise-sdk-go-zos">z/OS now supports Go</a>, and IBM even documents a process for porting programs to it, k6 is already a mature tool with a large codebase, and porting may not be as simple as modifying a Makefile. However, as I’ve alluded to before, Go being compiled to machine code may increase the chances of native compatibility, so long as we tell the compiler “hey — we’re running on z/OS”. In addition, the promise of being able to compile k6 just once and reusing that binary is enticing.</p><p>Porting a piece of software from one architecture to another is a daunting premise, especially with z/OS in the picture. While z/OS’s flavor of Unix — called Unix System Services- offers a lot of support for Unix software system calls, it is still not “just another ‘nix” like Arch or Debian, and there still remain unsupported features and encoding distinctions. Porting may not necessitate a lot of writing new code, but it does mandate a lot of trial and error with debugging, catching compiler errors, digging deep into configuration files and maintaining patience.</p><p>Well, as they say, we’ll cross that bridge when we get there. And it’s a winding bridge indeed, requiring us to grok the the recursive process of porting Go software to z/OS:</p><ol><li>Before porting a package, port its dependencies</li><li>For each dependency, follow (1)</li><li>Repeat (2) until all desired packages are compiled</li></ol><p>But we won’t know which packages are incompatible ’til we dive in headfirst. To start, I forked the k6 repository, then cloned it to a z/OS test machine. Our goal is a successful execution of go install for k6 — this command will compile the binary, move it to a predetermined $GOPATH/bin , and cache packages for future compilations.</p><p>I kicked off a go install within the k6 directory and awaited the oncoming storm of errors. Immediately it complained about an undefined syscall from the afero library, which is a filesystem framework and a dependency of k6.</p><pre> # github.com/spf13/afero<br>../go/pkg/mod/github.com/spf13/afero@v1.6.0/const_win_unix.go:26:15: <br>undefined: syscall.EBADFD</pre><p>As expected — before porting k6, we must port its dependencies. For addressing this undefined syscall, IBM’s docs suggest:</p><p><em>Look for files with build tags like ‘+build linux’ or ‘+build !linux’, which might need to add zos to the build tag: “+build linux zos” or “+build !linux,!zos”.</em></p><p>So I fork and clone the afero repository, added build flags for z/OS:</p><pre>// afero/const_bsds.go<br><br>// Before<br>// +build aix darwin openbsd freebsd netbsd dragonfly <br><br>// After<br>// +build aix darwin openbsd freebsd netbsd dragonfly zos</pre><p>then compiled afero first to ensure the compiler accepts these changes. For example:</p><pre>❯ cd afero<br>❯ go install<br>❯</pre><p>No errors. It compiled. Whoa.</p><p>We’re not done. Next, I had to editgo.modin the k6 repository. This file defines the modules that serve as dependencies for k6. When we compile k6, Go will also compile all the dependencies listed in go.mod, which is why we needed to validate that afero builds properly on z/OS first. We can quickly edit go.mod with the following</p><p>go mod edit -replace <a href="http://github.com/spf13/afero">github.com/spf13/afero</a> =&gt; /u/adam/afero</p><p>Now when we build k6, instead of pulling the afero dependency from the official repository, it will use our local version. Note that if the original module is already compatible with z/OS, this isn’t necessary.</p><p>We’ll try installing again. First, go mod vendor to sync the changes from go.mod , then go install.</p><pre>❯ go mod vendor<br>go: downloading github.com/sirupsen/logrus v1.9.0<br>go: downloading github.com/stretchr/testify v1.8.0<br>[...]<br>go: downloading github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f<br>go: downloading github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369<br>bash-4.3# go install<br># go.k6.io/k6/cmd<br>cmd/ui.go:322:12: undefined: getWinchSignal</pre><p>There’s yet another complaint regarding an undefined signal getWinchSignal . This time the call is coming from inside the house! Or more specifically— from the cmd module included in the k6 repository.</p><p>I’m not familiar with getWinchSignal , but digging into the source code for ui.go in k6 shows its relation to os.signal , which is connected to how Go handles Unix signals.</p><pre>if sig := getWinchSignal(); sig != nil {<br>          winch = make(chan os.Signal, 10)<br>          gs.signalNotify(winch, sig)<br>          defer gs.signalStop(winch)<br>      }</pre><p>Since this code is related to Unix-specific features, I am inclined to add another z/OS build flag just as we did for afero:</p><pre>// cmd/ui_unix.go<br><br>// Before<br>//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd<br><br>// After<br>//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || zos</pre><p>Since cmd is not an external module defined in go.mod , we can move onto running go install for k6 itself. Depending on what modules are already installed, one may need to execute additional downloads, for example:</p><pre>❯ go mod download cloud.google.com/go/storage<br>❯ go mod vendor</pre><p>After submitting these commands, we enter one last go install — and after a nail-biting eternity-spanning minute of waiting for the compiler to end its churning, there in the bin folder of GOPATH was our binary, neatly wrapped up and ready for us to use.</p><pre>❯ go install<br>❯ ls $GOPATH/bin<br>k6<br>❯ $GOPATH/bin/k6<br><br>          /\      |‾‾| /‾‾/   /‾‾/<br>     /\  /  \     |  |/  /   /  /<br>    /  \/    \    |     (   /   ‾‾\<br>   /          \   |  |\  \ |  (‾)  |<br>  / __________ \  |__| \__\ \_____/ .io<br><br>Usage:<br>  k6 [command]<br><br>Available Commands:<br>  archive     Create an archive<br>  cloud       Run a test on the cloud<br>  completion  Generate the autocompletion script for the specified shell<br>  help        Help about any command<br>  inspect     Inspect a script or archive<br>  login       Authenticate with a service<br>  pause       Pause a running test<br>  resume      Resume a paused test<br>  run         Start a load test<br>  scale       Scale a running test<br>  stats       Show test metrics<br>  status      Show test status<br>  version     Show application version<br><br>Flags:<br>  -a, --address string      address for the REST API server <br>  -c, --config string       JSON config file<br>  -h, --help                help for k6<br>      --log-format string   log output format<br>      --log-output string   change the output for k6 logs, possible values are stderr,stdout,none,loki[=host:port],file[=./path.fileformat] (default &quot;stderr&quot;)<br>      --no-color            disable colored output<br>  -q, --quiet               disable progress updates<br>  -v, --verbose             enable verbose logging<br><br>Use &quot;k6 [command] --help&quot; for more information about a command.</pre><p>Voila.</p><p>The above porting process is a compact recollection of my experience bringing k6 to z/OS. There were numerous other prerequisite hurdles — quirky Go installation paths, repository encodings, space requirements and so on—that are less relevant to porting Go programs to z/OS and more about growing pains that come with working with newer languages on z/OS Unix System Services.</p><p>Regardless of the challenges, once you’ve ported one piece of software, you’ve already grown accustomed to the necessary steps (build, fix, sync, repeat) to port other programs.</p><p>As for the above changes to afero and k6 — I’ve already opened the respective <a href="https://github.com/spf13/afero/pull/384">pull requests</a> for <a href="https://github.com/grafana/k6/pull/2892">both</a> so that those changes may be rolled upstream.</p><p>Go support on z/OS opens up a plethora of opportunities for bringing popular, performant, and practical utilities to the platform. With an <a href="https://www.ibm.com/docs/en/sdk-go-zos/1.17?topic=porting-applications-zos">easily documented</a> sequence of steps, I was able to compile a well-known cloud testing tool and deploy it in our own test environments, while fully leveraging the existing documentation and resources. It felt empowering and enjoyable working with and contributing to open-source software in the context of mainframes.</p><p>I am eager to delve more in-depth about our advanced usage of k6 in z/OS testing, but for now, we can cherish our Go-rgeous victory.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*Fxg1f4baplCNo9PY.gif" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f7f73267c1c" width="1" height="1" alt=""><hr><p><a href="https://medium.com/theropod/go-ing-native-porting-grafana-k6-to-z-os-with-go-f7f73267c1c">Go-ing Native: Porting Grafana k6 to z/OS with Go</a> was originally published in <a href="https://medium.com/theropod">Theropod</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[The Black American Mecca You’ve Never Heard of]]></title>
            <link>https://medium.com/@msradam/the-black-american-mecca-youve-never-heard-of-f07e4a0a1fde?source=rss-20a23703cc5d------2</link>
            <guid isPermaLink="false">https://medium.com/p/f07e4a0a1fde</guid>
            <category><![CDATA[black-wall-street]]></category>
            <category><![CDATA[civil-rights]]></category>
            <category><![CDATA[black-history-month]]></category>
            <category><![CDATA[tulsa-race-massacre]]></category>
            <dc:creator><![CDATA[Adam]]></dc:creator>
            <pubDate>Sun, 29 Jan 2023 18:43:15 GMT</pubDate>
            <atom:updated>2023-01-29T18:43:15.666Z</atom:updated>
            <content:encoded><![CDATA[<p><em>This is a reprint of a piece I’ve published in Oct 2016, and reflects my writing style from that time period. Minor edits have been made for clarity. Its message is still relevant. The views expressed here are solely my own.</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*38Y6g0TfWcUCZTKc" /></figure><p>A 20th Century paradise, built from the ground up, sustained entirely by an overwhelmingly Black American population.</p><p>This ‘Black Wall Street’ was packed with business centers, hotels, cafes, shopping malls, high-performing schools and homes featuring modern conveniences.</p><p>You probably never heard of this place, the suburban community of Greenwood in Tulsa, Oklahoma. It may not have been in any history textbook you’ve read, or Netflix documentary you watched at 3 in the morning. It might not have even been brought up during Black History Month, despite all the lip service paid to figures like MLK Jr. and Malcolm X.</p><p>A thriving, technologically superior black neighborhood. Empowering and inspirational, especially considering the rhetoric spat out by politicians and media figures concerning the black community, even today.</p><p>As a South Asian immigrant, my presence in academic institutions and workplaces communicates the ‘model minority’ narrative to society, that my family and individuals like me are ‘inherently’ capable of uplifting ourselves out of rigid socioeconomic conditions through intellect and grit.</p><p>This same narrative is not granted to black Americans, however, who are vilified in the media as being disadvantaged due to their own accord. The renowned “<a href="http://www.blackwallstreet.freeservers.com/The%20Story.htm">Black Wall Street</a>” says otherwise, but unfortunately, it seems there is great care in wiping it off the record. Just as it had been wiped off the map.</p><p>Indeed, on May 31st and <a href="http://sfbayview.com/2011/02/what-happened-to-black-wall-street-on-june-1-1921/">June 1st of 1921</a>, members of the white community in Tulsa carried out a vicious attack on ground and from the air on the African-American community. Over 30 blocks of the neighborhood were demolished by airstrikes and bombs, 300 black people were killed, 800 admitted to hospitals, and over 6,000 were detained.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*cA3VDv_u8G4O2yq5.jpg" /></figure><p>For the black veterans of WWI, they would have been reliving the horrors of combat in their own neighborhood. Dynamite, turpentine bombs, machine guns, gas…. all were being deployed by American citizen unto American citizen. Later investigations showed the city of Tulsa to have conspired with the white mob, hence why no fire alarms sounded and why police joined in, firing machine guns into the black crowd. A travesty.</p><p>The former success of Greenwood and the massacre’s events were given no mention in town, city or state histories. Although it had been initiated after armed black citizens were attempting to prevent a lynching at the police station, historical records at the time shifted the blame towards the black population for ‘instigating the riot’.</p><p>Such was the story of Greenwood and its accompanying massacre, unheard of for almost eight decades until 1996 when the state legislature established the <a href="http://greenwoodculturalcenter.com/">Tulsa Race Riot Commission </a>to gather survivors’ anecdotes, collect more information and correct the historical record. They even recommended reparations to the survivors’ descendants.</p><p>Still, this event is not taught enough and its history must be proliferated. Students and society in general need to understand this one instance of black American brilliance, and how swiftly it was taken away as white citizens and the State conspired acts of domestic terrorism.</p><p>African-Americans and their allies must keep the memory of Black Wall Street in their hearts, for the goal of the Black Lives Matter movement and Civil Rights in general is to remove the notion that ‘Black’ and ‘Wall Street’ do not belong in the same sentence.</p><p>That the principles of hard work and self-sufficiency definitely do apply to black communities. That the state has taken an active hand in preventing the upward mobility of these communities by reinforcing systems of segregation through economic policy and mass incarceration.</p><p>So when politicians and media figures stand up at the podium and talk down to Black Americans while burning the image of devastated and violent black communities into the collective unconscious, we know better. We must engage in collective remembrance and retell the story of the minority experience in America. Do not forget.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*I-qCvtfZ9-Q-ljhE.jpg" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f07e4a0a1fde" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Swarming Stressed Servers: Open-Source Load-Testing on z/OS Mainframes with Locust]]></title>
            <link>https://medium.com/theropod/swarming-stressed-servers-open-source-load-testing-on-z-os-mainframes-with-locust-42a1d5e3363e?source=rss-20a23703cc5d------2</link>
            <guid isPermaLink="false">https://medium.com/p/42a1d5e3363e</guid>
            <category><![CDATA[open-source]]></category>
            <category><![CDATA[load-testing]]></category>
            <category><![CDATA[mainframe]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[ibm]]></category>
            <dc:creator><![CDATA[Adam]]></dc:creator>
            <pubDate>Tue, 17 Jan 2023 14:03:57 GMT</pubDate>
            <atom:updated>2023-01-17T20:51:55.531Z</atom:updated>
            <content:encoded><![CDATA[<p>🖥🖥 It’s 6 pm. I scan my text editor to paint the finishing whitespace on my test script. Satisfied, I swap to a terminal window and hit enter. In a second, thousands of requests cascade upon the screen, each acting out the life of a user. They hit our server with a stream of queries, submitting and creating hundreds and thousands of tasks and files. I smile — here comes the swarm.</p><p>But what are we swarming, and why? The ‘what’ is an IBM Z mainframe running z/OS. The ‘why’ requires a bit more explanation.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/580/1*PwarGcLlnZLi7I2_tFGdnA.png" /></figure><p>Mainframes necessitate large-scale transaction processing. They must handle the millions upon millions of daily requests and responses that power the financial, manufacturing, transportation industries, among others. This means sustaining a large number of concurrent users and transactions per second while ensuring consistent availability. For example, financial institutions have been known to deploy mainframes to support the huge quantity of credit card transactions they need to transmit, process, and store.</p><p>As a z/OS Systems Tester, my work on a mainframe OS does not begin and end with validating the input and output of a function. I must verify if such functions can handle the necessary stress that a mainframe workload might induce. As we introduce several new functions to our test systems, we want to regression test these new features to ensure they do not break existing ones, making certain these functions still behave as expected, especially under load.</p><p>Simulating load on the system can help preemptively identify bugs and resource shortages. Remember those websites getting hammered with thousands of orders for sneakers or a PS5, and buckling under the load of demand? By testing for these scenarios, including edge-cases where demand suddenly spikes, one can ensure their server stays up and running on D-Day. Consider a load test a rehearsal, with the tester the director — deciding what type of requests are sent, during which times, how often, and what responses to expect.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/275/1*LVuzxT0fFi9RnhWiKMZ1ng.png" /></figure><p>Having established what a load test is, it’s time to pick a tool from our toolbox. In addition to the custom internal test frameworks we’ve developed over decades, there exist open-source and more ubiquitous tools, such as Apache JMeter, Locust, Gatling, and Grafana k6. These tools are intended to load test web servers that expose REST APIs, and are extensible, enabling us to load test certain z/OS functions provided there is an API endpoint we can submit requests to. These tools present additional advantages to our internal ones, like being able to script testcases in popular languages such as Python and JavaScript, and more seamlessly integrating into our CI/CD pipelines and source control management.</p><p>When starting out writing load tests for z/OS, I chose Locust for its more straightforward Python-based syntax. Behavior for each simulated user is specified in a Python script, e.g.</p><pre># locustfile.py<br>from locust import HttpUser<br><br>class WebsiteUser(HttpUser):<br>    def on_start(self):<br>        self.client.post(&quot;/login&quot;, {<br>            &quot;username&quot;: &quot;test_user&quot;,<br>            &quot;password&quot;: &quot;test_password&quot;<br>        })</pre><p>The WebsiteUser performs a simple task — upon initialization, submit a post request to the /login endpoint, with username and password included in the request payload.</p><p>Some arguments Locust accepts for its load test parameters include:</p><ul><li>-H — The host Locust will target, in the form of a URL</li><li>-u — The number of simulated users</li><li>-r — Rate at which users spawn per second</li><li>-t — Total duration of the run</li><li>— headless —Execute the test exclusively from the command line, without opening up a web UI</li></ul><p>For example, to execute a one hour long test with our WebsiteUser against example.com with 100 simulated users, spawning at 10 users a second and running only the command line, we’d enter the following command.</p><pre>$ locust -f locustfile.py -H example.com -u 100 -r 10 -t 3600s --headless</pre><p>Now that we have an understanding of how Locust works, how can we use it to target our mainframes? After all, Locust is intended to target web API endpoints, while z/OS is known for its green screen terminals.</p><p>Thankfully, there’s the z/OS Management Facility — z/OSMF. This software provides a framework for executing system tasks via web interface — and it also exposes a REST API for z/OS functions. The z/OSMF server is a task that runs on z/OS, and is able to submit jobs, create data sets, and send console commands.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/703/1*fDRONq9xj0Zpdx3mCD1RpA.png" /></figure><p>Table 1 lists two job-related operations a user can perform by submitting GET requests to a specific HTTPS endpoint. Traditionally, submitting a z/OS job (i.e. a task or process that can be run in batch) requires logging on to a 3270 green-screen terminal, but now it can also be automated through REST APIs — therefore making a perfect candidate for user behavior our load test can simulate.</p><p>Here’s a snippet of how we can use Locust to submit jobs to z/OS:</p><pre>test_jobs = [&quot;//TESTSC JOB (),MSGCLASS=H\n// EXEC PGM=IEFBR14&quot;, <br>             &quot;//TESTSB JOB (),MSGCLASS=H\n// EXEC PGM=BPXBATCH,PARM=&#39;sh sleep &quot; + str(random.randint(10,30)) + &quot;&#39;&quot;,<br>             &quot;//TESTSC JOB (),MSGCLASS=H\n// EXEC PGM=BPXBATCH,PARM=&#39;sh echo HiFromRest&#39;&quot;]<br>  <br>class JobsUser(HttpUser):<br>    @task<br>    def on_start(self):<br>         with self.client.put(&quot;zosmf/restjobs/jobs&quot;, headers=headers, data=random.choice(test_jobs), catch_response=True, auth=(USERNAME,PASSWORD),verify=False) as response:<br>             print(&quot;Submitted &quot; + response.json()[&#39;jobname&#39;] + &quot; with job ID &quot; + response.json()[&#39;jobid&#39;] + &quot;. &quot; + response.json()[&#39;phase-name&#39;])</pre><p>First, we define a list of strings representing a test job. The jobs are written in Job Control Language (JCL), a scripting language to specify instructions for z/OS batch jobs, which our system will parse and execute. These sample jobs will either perform nothing, execute shell commands to sleep for a certain period of time, or print text to the z/OS Unix shell.</p><p>When a new JobsUser is spawned, it will send a PUT request to the zosmf/restjobs/jobs endpoint, along with the necessary authorization and headers, randomly select a test job from the list, and include that string in its payload.</p><p>The z/OSMF server will accept the PUT and read in the JCL from the string passed in by the request, and the result is captured in the response variable. We can retrieve data from that response to check the status of our job and print its output. For example, we can check if our job is in the OUTPUT queue, which confirms our job completed processing, and set a corresponding variable. This lets us validate proper submission, execution, and output for all jobs submitted by each user, confirming that the server is properly handling all the requests when under load.</p><pre>                  if response.json()[&#39;status&#39;] == &#39;OUTPUT&#39;:<br>                      job_complete = True</pre><p>Now all the pieces are in place. We have a reliable tool in Locust to create user scripts for our load tests, and we have a server to run our load tests against in the form of z/OSMF. This enables an expansive breadth and depth of testcases, for example, have hundreds of users submitting thousands of jobs over a 24 hour period, or have thousands of users writing to files on the system with 1 user spawning every 2 minutes for two days.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/685/1*6a5sBMfQwLHsTVKSkgV4Jg.gif" /></figure><p>Simulating activity on a mainframe can seem daunting at first, but by leveraging existing open-source tools and the latest z/OS features, we have an accessible, extensible, and effective means of generating load on our servers. We can stamp out the bugs to come, with a swarm of our own.</p><p><em>Special thanks to Frank De Gilio, Michael Gildein, Anthony Giorgio, and Luisa Martinez for assisting in the writing and publication of this article.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=42a1d5e3363e" width="1" height="1" alt=""><hr><p><a href="https://medium.com/theropod/swarming-stressed-servers-open-source-load-testing-on-z-os-mainframes-with-locust-42a1d5e3363e">Swarming Stressed Servers: Open-Source Load-Testing on z/OS Mainframes with Locust</a> was originally published in <a href="https://medium.com/theropod">Theropod</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Sacred Geometry: On Directing Ayad Akhtar’s ‘Disgraced’]]></title>
            <link>https://medium.com/@msradam/sacred-geometry-on-directing-ayad-akhtars-disgraced-fefe79de6c39?source=rss-20a23703cc5d------2</link>
            <guid isPermaLink="false">https://medium.com/p/fefe79de6c39</guid>
            <category><![CDATA[directing]]></category>
            <category><![CDATA[theatre]]></category>
            <category><![CDATA[play]]></category>
            <category><![CDATA[wesleyan-university]]></category>
            <category><![CDATA[social-justice]]></category>
            <dc:creator><![CDATA[Adam]]></dc:creator>
            <pubDate>Wed, 14 Aug 2019 15:15:28 GMT</pubDate>
            <atom:updated>2019-08-14T15:15:28.303Z</atom:updated>
            <content:encoded><![CDATA[<h3>Sacred Geometry: On Directing Ayad Akhtar’s ‘Disgraced’ at Wesleyan</h3><p>There is an unmatched clarity to creating art from limitation.</p><p>In my Wesleyan junior fall, I seized such an opportunity. I directed the very play that thrust me into the realm of theater.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/850/0*6l62X0KQDecp6mik.jpg" /><figcaption>“Stained Glass”, by yours truly.</figcaption></figure><p>Ayad Akhatar’s “Disgraced” was first presented to me as an opportunity to leverage my identity as a young Desi male and perform several times as Hussein Malik / Abe Jensen, whose experience mirrors my own (to an extent, thankfully). The Readers’ Theater of Connecticut had reached out to Wesleyan’s Muslim Chaplain and to its Theater Dept. querying for someone who fit the description (a rare moment where, for a man of color, ‘fit the description’ was something undeniably positive).</p><p>At that time, I ached to act and probably would have accepted any role. I remember my freshman self dashing to the Office of Religious Life to meet with directors Anne Cassady and Richard Kamins, clearing my throat to try out for the part. No knowledge or preparation of the play beforehand, I was essentially cast because I was one of the first and only people to have responded to their casting call.</p><p>Fast forward to two years later; I was handing out sides for the parts I had grown to know almost as people in their own right. In my head, ‘Isaac’, ‘Jory’, ‘Abe’, ‘Emily’, and especially ‘Amir’ were real, and spoke to me, and each of them was the type of person who would be indignant if I botched their casting.</p><p>I’d like to say I didn’t! I wouldn’t know, for as I was steeped in weeks of rehearsal, the actors in front of me grew into their roles so well that, as far as I was concerned, they <em>were</em> the characters, just as I had become ‘Abe’ when I embodied him years prior.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/834/0*ZR7UUJOcaQqof52v.png" /><figcaption>A directing moment.</figcaption></figure><p>It was not a seamless beauty. We were, after all, university students (and in the case of one of my cast, a university employee) for whom top grades and career aspirations were the priority. Second Stage, the production company sponsoring my play, is volunteer-based and entirely student-run, and our entire cast and crew had limited experience in theatrical production.</p><p>This was my first time directing, and although professional directing experience was available on Wesleyan’s campus in the form of Directing I, II, and other courses, these were essentially inaccessible to me. I had always seen my theater major as a separate and smaller interest from my career path in software, I had never imagined that I would end up being one of the individuals on campus who would run a theater company, act in major productions, and direct a play.</p><p>Seven courses, frequent physical therapy, being the lights liaison of a major production company, and directing a play. And yet, I felt an odd sort of freedom, the kind where I was able to choose my own pain and look forward to seeing this production come together.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/850/0*vO9ftP0eQOlbRdbe.jpg" /><figcaption>Statue of the Hindu goddess Shiva, a highlighted prop.</figcaption></figure><p>Personal and logistic limitations lent the play a unique authenticity, a sense of things being handcrafted and incidental. The stage was not a grand proscenium but an improvised black box in the basement of Wesleyan’s Malcolm X House. The lavish NYC apartment Akhtar describes was framed by pieces of furniture borrowed both from the Center for the Arts, the office of Wesleyan’s theater technical director, and people’s personal possessions. My lack of experience as the lights liaison meant I could barely figure out how to actually bring theatrical lights into the space, so off to Ikea we went to obtain remote controlled lighting peripherals, and off to my room I went to grab my floor lamp.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/850/0*Mmzl-Wqw0a6sW9b6.jpg" /><figcaption>Isaac (played by Skye Hawthorne) and Emily (played by Ava Biery)</figcaption></figure><p>But, I mean, Jesus. <em>Subhanallah</em>.</p><p>I’m still in disbelief at how ragtag the process was and yet how cohesive the final product felt. Our limitations brought out a collective genius, where my team’s experience in film and art translated to selecting the perfect wallpapers, furniture pieces, and props that could coexist in this communally crafted microcosm.</p><p>The aesthetic was a vibrant yet classy red, white, and dark shades of navy and black which cohered with the costume design and complemented by geometric patterns; the jazzy sound design provided this with a greater reality, ambience that cast judgment on the characters themselves. The set was flanked on the northeast by a handbuilt balcony setpiece that my set designer Angelica and her volunteer carpenters toiled to make which lent the illusion of an outer world, a clever method of masking the shattered glass prop that Arnaav needed to toss to the floor in a fit of rage.</p><p>There not being any theatrical incandescent lighting meant the set needed to be lit entirely by ‘naturals’ — a small table lamp near the ‘fireplace’, a floor lamp from my room, and LED strip lights near the ‘lobby’ — all of which were tethered to wireless light dimmers that needed to be on cue with certain moments. This ended up being a rather cool element; even though audiences were familiar with how theatrical lighting systems were set up with lightboards and specialized software, our system was entirely improvised and home-made and set within the confines of this residential area. The space was truly transformed.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/850/0*k4UIW-0tQ7OwnSNF.jpg" /><figcaption>Emily and Amir (played by Arnaav Bhavanani)</figcaption></figure><p>I miss it, of course. I burn with nostalgia at this halcyonic winter, where I was provided both with freedom and restriction to collaborate and create a work of art that adhered so much to personal identity yet was blessed with community. It was a lighting flash, a moment trapped in amber and cast in flame. It could only have happened in my final year of college with this collective of individuals in particular.</p><p>I don’t know if I am even a good theatermaker, if I am a decent actor or director, but I know that I enjoyed seeing the final product, and I know that I ache with a desire to do more. Even in the midst of writing this, there is more that I want to say (specifically about <em>why</em> ‘Disgraced’ deserves a Pulitzer, but that is for another time).</p><p>A final thank you to all of the individuals mentioned here, my cast and crew, my team. Some of the artists of the future are mentioned in this very program. To them, I give much 💕.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/510/0*1G5LjlhQazUpfP68.png" /></figure><p><em>Official publicity photographs courtesy of Elijah Comas ‘22</em></p><p><em>That adorable directing photo courtesy of my Stage Manager Thanmye Lagudu ‘20.</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/850/0*RnY6lKI0eMsc0b9Q.jpg" /></figure><p><em>This article is also featured on my personal website and blog </em><a href="http://adamr.io"><em>http://adamr.io</em></a><em> — check it out. :)</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=fefe79de6c39" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[The Roads Yet Taken: My UNICEF Winternship | Part I]]></title>
            <link>https://medium.com/@msradam/the-roads-yet-taken-my-unicef-winternship-part-i-e12f91d9b37c?source=rss-20a23703cc5d------2</link>
            <guid isPermaLink="false">https://medium.com/p/e12f91d9b37c</guid>
            <category><![CDATA[internships]]></category>
            <category><![CDATA[unicef]]></category>
            <category><![CDATA[computer-science]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[programming]]></category>
            <dc:creator><![CDATA[Adam]]></dc:creator>
            <pubDate>Thu, 11 Jul 2019 15:43:33 GMT</pubDate>
            <atom:updated>2019-07-11T15:43:33.735Z</atom:updated>
            <content:encoded><![CDATA[<p>In my mother’s childhood, when Bangladesh herself was newly-born, her father would bring home blankets emblazoned with the UNICEF logo, a comforting blue. This same blue, painted on the canvas banners of the UNICEF lobby, where I waited for my supervisor Mike Fabrikant to sign me in for my first day as a Software Engineering intern.</p><p>As I leaned against the couch in the lobby, I traced a route in my mind’s eye — from the Dhaka hospital where I was born, to the teensy-weensy lead-chipped apartment my parents and I sidled into when we arrived here in the new millennium, to the finale of my academic career at Wesleyan where I finished up my B.A. in Computer Science and Theater.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1000/1*nX3YvKv1MmTNc7KUbvPYtg.jpeg" /><figcaption>The UNICEF building — a place that would continue to inspire me.</figcaption></figure><p>“How did I get here?”</p><p>This question was fueled by a Matcha-Yerba Mate infusion I had concocted that morning, heated with a silent prayer that the pen-and-paper knowledge gained from my Computer Science courses would translate well to this particular opportunity. My internship was already on its way; just a week after final exams ended that semester, I was installing React packages and running Docker containers to view UNICEF’s MagicBox platform for myself.</p><p>MagicBox is an open-source multifaceted collaborative platform for aggregating, ingesting, and understanding the big data corresponding to specific phenomena in UNICEF programme countries, from connectivity to disease outbreaks. Crafting visualizations and developing machine learning models from the data collected can go a long way in predicting and planning for natural disasters, epidemics, or other exogenous factors that may disrupt wellbeing.</p><p>I knew quite well about the phenomena faced by developing countries on the other side of the world — whether it be my performative writing seminar where race and class was on everyone’s breath, or my course on social entrepreneurship and philanthropy — Bangladesh and/or its third-world problems were a persistent thread. Having moved to the U.S. so young, I was only familiar with the sensations of my country of origin — the heat and humidity, the fabrics and clear skies — distinct from the powerful and monolithic view of the United Nations towers from the UNICEF innovation office.</p><p>There, Mike and my other supervisor, Marcella Maki, helped me discern my route through this internship, which was partly remote and partly onsite. My fellow intern, Courage Angeh, was working remotely from Cameroon, which made for an interesting dynamic as I was often one of two interns present in the UNICEF Innovation offices.</p><p>I couldn’t believe how fortunate I was, that I’d be able to look after my family and prepare for my final semester at Wesleyan while transmuting the conceptual into the concrete. These next two months were spent in a deep dive of scientific computing, geospatial analysis, virtual machines, and plenty of tea — of course. In Part II of this piece, I will describe how I tackled healthsite accessibility, the challenges faced, and why it affirmed my desire to code with purpose.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*6DMC1VQbQ2s2SqzvJYQZTQ.jpeg" /><figcaption>Me and my supervisor, <a href="https://medium.com/u/f8b0541e5c00">Mike Fabrikant</a>.</figcaption></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e12f91d9b37c" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>