text:
Creative Commons Legal Code

CC0 1.0 Universal

    CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
    LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
    ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
    INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
    REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
    PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
    THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
    HEREUNDER.

Statement of Purpose

The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator
and subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").

Certain owners wish to permanently relinquish those rights to a Work for
the purpose of contributing to a commons of creative, cultural and
scientific works ("Commons") that the public can reliably and without fear
of later claims of infringement build upon, modify, incorporate in other
works, reuse and redistribute as freely as possible in any form whatsoever
and for any purposes, including without limitation commercial purposes.
These owners may contribute to the Commons to promote the ideal of a free
culture and the further production of creative, cultural and scientific
works, or to gain reputation or greater distribution for their Work in
part through the use and efforts of others.

For these and/or other purposes and motivations, and without any
expectation of additional consideration or compensation, the person
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
is an owner of Copyright and Related Rights in the Work, voluntarily
elects to apply CC0 to the Work and publicly distribute the Work under its
terms, with knowledge of his or her Copyright and Related Rights in the
Work and the meaning and intended legal effect of CC0 on those rights.

1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not
limited to, the following:

  i. the right to reproduce, adapt, distribute, perform, display,
     communicate, and translate a Work;
 ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or
     likeness depicted in a Work;
 iv. rights protecting against unfair competition in regards to a Work,
     subject to the limitations in paragraph 4(a), below;
  v. rights protecting the extraction, dissemination, use and reuse of data
     in a Work;
 vi. database rights (such as those arising under Directive 96/9/EC of the
     European Parliament and of the Council of 11 March 1996 on the legal
     protection of databases, and under any national implementation
     thereof, including any amended or successor version of such
     directive); and
vii. other similar, equivalent or corresponding rights throughout the
     world based on applicable law or treaty, and any national
     implementations thereof.

2. Waiver. To the greatest extent permitted by, but not in contravention
of, applicable law, Affirmer hereby overtly, fully, permanently,
irrevocably and unconditionally waives, abandons, and surrenders all of
Affirmer's Copyright and Related Rights and associated claims and causes
of action, whether now known or unknown (including existing as well as
future claims and causes of action), in the Work (i) in all territories
worldwide, (ii) for the maximum duration provided by applicable law or
treaty (including future time extensions), (iii) in any current or future
medium and for any number of copies, and (iv) for any purpose whatsoever,
including without limitation commercial, advertising or promotional
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
member of the public at large and to the detriment of Affirmer's heirs and
successors, fully intending that such Waiver shall not be subject to
revocation, rescission, cancellation, termination, or any other legal or
equitable action to disrupt the quiet enjoyment of the Work by the public
as contemplated by Affirmer's express Statement of Purpose.

3. Public License Fallback. Should any part of the Waiver for any reason
be judged legally invalid or ineffective under applicable law, then the
Waiver shall be preserved to the maximum extent permitted taking into
account Affirmer's express Statement of Purpose. In addition, to the
extent the Waiver is so judged Affirmer hereby grants to each affected
person a royalty-free, non transferable, non sublicensable, non exclusive,
irrevocable and unconditional license to exercise Affirmer's Copyright and
Related Rights in the Work (i) in all territories worldwide, (ii) for the
maximum duration provided by applicable law or treaty (including future
time extensions), (iii) in any current or future medium and for any number
of copies, and (iv) for any purpose whatsoever, including without
limitation commercial, advertising or promotional purposes (the
"License"). The License shall be deemed effective as of the date CC0 was
applied by Affirmer to the Work. Should any part of the License for any
reason be judged legally invalid or ineffective under applicable law, such
partial invalidity or ineffectiveness shall not invalidate the remainder
of the License, and in such case Affirmer hereby affirms that he or she
will not (i) exercise any of his or her remaining Copyright and Related
Rights in the Work or (ii) assert any associated claims and causes of
action with respect to the Work, in either case contrary to Affirmer's
express Statement of Purpose.

4. Limitations and Disclaimers.

 a. No trademark or patent rights held by Affirmer are waived, abandoned,
    surrendered, licensed or otherwise affected by this document.
 b. Affirmer offers the Work as-is and makes no representations or
    warranties of any kind concerning the Work, express, implied,
    statutory or otherwise, including without limitation warranties of
    title, merchantability, fitness for a particular purpose, non
    infringement, or the absence of latent or other defects, accuracy, or
    the present or absence of errors, whether or not discoverable, all to
    the greatest extent permissible under applicable law.
 c. Affirmer disclaims responsibility for clearing rights of other persons
    that may apply to the Work or any use thereof, including without
    limitation any person's Copyright and Related Rights in the Work.
    Further, Affirmer disclaims responsibility for obtaining any necessary
    consents, permissions or other rights required for any use of the
    Work.
 d. Affirmer understands and acknowledges that Creative Commons is not a
    party to this document and has no duty or obligation with respect to
    this CC0 or use of the Work.

repo_name: kdeldycke/awesome-falsehood

mime_type: text/plain


text:
    Yᴏᴜʀ Dᴇᴠᴇʟᴏᴘᴇʀ Pʀᴏᴅᴜᴄᴛ ʜᴇʀᴇ!

    Add a link to your company or project here: back me up via a GitHub sponsorship.

---

  The logic of the world is prior to all truth and falsehood.

  — Ludwig Wittgenstein[1]

A curated [![Awesome](https://awesome.re/badge-flat.svg)](https://github.com/sindresorhus/awesome) list of falsehoods programmers believe in. A *falsehood* is an ***idea* that you initially believed was true**, but in reality, it is **proven to be false**.

E.g. of an *idea*: valid email address exactly has one `@` character. So, you will use this rule to implement your email-field validation logic. Right? Wrong! The *reality* is: emails can have multiple `@` chars. Therefore your implementation should allow this. The initial *idea* is a falsehood you believed in.

The *falsehood* articles listed below will have a comprehensive list of those false-beliefs that you should be aware of, to help you become a better programmer.

## Contents

- [Meta](#meta)
- [Arts](#arts)
- [Business](#business)
- [Cryptocurrency](#cryptocurrency)
- [Dates and Time](#dates-and-time)
- [Education](#education)
- [Emails](#emails)
- [Geography](#geography)
- [Human Identity](#human-identity)
- [Internationalization](#internationalization)
- [Management](#management)
- [Multimedia](#multimedia)
- [Networks](#networks)
- [Phone Numbers](#phone-numbers)
- [Postal Addresses](#postal-addresses)
- [Science](#science)
- [Society](#society)
- [Software Engineering](#software-engineering)
- [Transportation](#transportation)
- [Typography](#typography)
- [Video Games](#video-games)
- [Web](#web)

## Meta

- [Falsehoods Programmers Believe](https://spaceninja.com/2015/12/07/falsehoods-programmers-believe/) - A brief list of common falsehoods. A great overview and quick introduction into the world of falsehoods.
- [Falsehoods about Programming](https://chiselapp.com/user/ttmrichter/repository/gng/doc/trunk/output/falsehoods.html) - A humbling and fun list on programming and programmers themselves.
- [Falsehoods about Falsehoods Lists](https://kevin.deldycke.com/2016/12/falsehoods-programmers-believe-about-falsehoods-lists/) - Meta commentary on how these falsehoods shouldn't be handled.

## Arts

- [Falsehoods about Music](https://literateprogrammer.blogspot.fr/2016/07/falsehoods-programmers-believe-about.html) - False assumption that might be made in codifying music.
- [Falsehoods about Art](http://artsy.github.io/blog/2018/04/18/programmer-misconceptions-about-art/) - Common misconceptions about art.

## Business

- [Falsehoods about Online Shopping](https://wiesmann.codiferes.net/wordpress/archives/22201) - Covers prices, currencies and inventory.
- [Falsehoods about Prices](https://gist.github.com/rgs/6509585) - Covers currencies, amounts and localization.
- [Falsehoods about IBANs](https://github.com/globalcitizen/php-iban/blob/master/docs/FALSEHOODS.md) - International Bank Account Numbers are not international.
- [Falsehoods about Economics](http://exple.tive.org/blarg/2016/09/22/falsehoods-programmers-believe-about-economics/) - Economics are not simple or rational.
- [Decimal Point Error in Etsy's Accounting System](https://www.reddit.com/r/Etsy/comments/hz4877/if_you_are_an_etsy_seller_do_not_purchase_postage/) - The importance of types in accounting software: missing the decimal point ends up with 100x over-charges.
- [Twenty five thousand dollars of funny money](http://rachelbythebay.com/w/2022/12/02/25k/) - Same error as above at Google Ads, or the danger of separating your pennies from your dollars, where $250 internal coupons turned into $25,000. My advice: [get rid of integers and floats for monetary values. Use decimals. Or fallback to strings and parse them, don't validate.](https://twitter.com/kdeldycke/status/1599113889093890049)
- [Characters `<` and `>` in company names lead to XSS attacks](https://forum.aws.chdev.org/t/cross-site-scripting-xss-software-attack/3355) - Because [UK allows companies to be registered with special characters](https://www.legislation.gov.uk/uksi/2015/17/schedule/1/made), a hacker leveraged them to register `\"><SCRIPT SRC=MJT.XSS.HT></SCRIPT> LTD`, but also `; DROP TABLE "COMPANIES";-- LTD`, `BETTS & TWINE LTD` and `SAFDASD & SFSAF \' SFDAASF\" LTD`.
- [Minutiae of company names](https://twitter.com/nthnmsmth/status/1587880523124408322) - How the rules of the State of Delaware and the IRS does not intersects.
- [CLDR currency definitions](https://github.com/unicode-org/cldr/blob/release-40/common/supplemental/supplementalData.xml#L87-L94) - Currency validity date ranges overlap due to revolts, invasions, new constitutions, and slow planned adoption.
- [`tax`](https://github.com/commerceguys/tax) - A PHP 5.4+ tax management library.

## Cryptocurrency

- [Falsehoods about Bitcoin](https://github.com/theborakompanioni/spring-boot-bitcoin-starter/blob/master/docs/FALSEHOODS.md) - A list of mistaken perspectives on Bitcoin.
- [Falsehoods about Ethereum](https://gist.github.com/spalladino/a349f0ca53dbb5fc3914243aaf7ea8c6) - Misconceptions and common pitfalls in contract programming.

## Dates and Time

- [Falsehoods about Time](http://infiniteundo.com/post/25326999628/falsehoods-programmers-believe-about-time) - Seminal article on dates and time.
- [More Falsehoods about Time](http://infiniteundo.com/post/25509354022/more-falsehoods-programmers-believe-about-time) - Part. 2 of the article above.
- [Falsehoods about Time and Time Zones](https://www.creativedeletion.com/2015/01/28/falsehoods-programmers-date-time-zones.html) - Another takes on time-related falsehoods, with an emphasis on time zones.
- [Critique of Falsehoods about Time](https://gist.github.com/thanatos/eee17100476a336a711e) - Takes on the first article above and provides an explanation of each falsehood, with more context and external resources.
- [Falsehoods about Unix Time](https://alexwlchan.net/2019/05/falsehoods-programmers-believe-about-unix-time/) - Mind the leap second!
- [Falsehoods about Time Zones](https://www.zainrizvi.io/blog/falsehoods-programmers-believe-about-time-zones/) - Has some nice points regarding the edge-cases of DST transitions.
- [Your Calendrical Fallacy Is Thinking…](http://yourcalendricalfallacyis.com) - List covering intercalation and cultural influence, made by a community of iOS and macOS developers.
- [Time Zone Database](https://www.iana.org/time-zones) - Code and data that represent the history of local time for many representative locations around the globe.
- [The Long, Painful History of Time](http://naggum.no/lugm-time.html) - Most of the idiosyncrasies in timekeeping can find an explanation in history.
- [You Advocate a Calendar Reform](https://qntm.org/calendar) - Your idea will not work. This article tells you why.
- [So You Want to Abolish Time Zones](https://qntm.org/abolish) - Abolishing timezones may sound like a good idea, but there are quite a few complications that make it not quite so.
- [The Problem with Time & Timezones](https://www.youtube.com/watch?v=-5wpm-gesOY) - A video about why you should never, ever deal with timezones if you can help it.
- [\$26,000 Overcollection by Labor Department](http://digital.vpr.net/post/rounding-error-computer-code-leads-26000-overcollection-labor-department) - The consequence of wrong calendar accounting.
- [RFC-3339 vs ISO-8601](https://ijmacd.github.io/rfc3339-iso8601/) - An giant list of formats from the two standards, how they overlaps, and live examples.
- [ISO-8601, `YYYY`, `yyyy`, and why your year may be wrong](https://ericasadun.com/2018/12/25/iso-8601-yyyy-yyyy-and-why-your-year-may-be-wrong/) - String formatting of date is hard.
- [UTC is Enough for everyone, right?](https://zachholman.com/talk/utc-is-enough-for-everyone-right) - There are edge cases about dates and time (specifically UTC) that you probably haven't thought of.
- [Storing UTC is not a silver bullet](https://codeblog.jonskeet.uk/2019/03/27/storing-utc-is-not-a-silver-bullet/) - “Just store dates in UTC” is not always the right approach.
- [How to choose between UT1, TAI and UTC](https://news.ycombinator.com/item?id=28047376) - Depends on your priorities between SI seconds, earth rotation sync, leap seconds avoidance.
- [Why is subtracting these two times (in 1927) giving a strange result?](https://stackoverflow.com/a/6841479/57311) - Infamous Stack Overflow answer about both complicated historical timezones, and how historical dates can be re-interpreted by newer versions of software.
- [Critical and Significant Dates](https://web.archive.org/web/20150908004245/http://www.merlyn.demon.co.uk/critdate.htm) - From Y2K to the overflow of 32-bit seconds from Unix epoch, a list of special date to watch for depending on the system.
- “I'm going to a commune in Vermont and will deal with no unit of time shorter than a season.” - Is the note left on his terminal by a quitting engineer in the 70s, after too much effort toiling away on sub-second timing concerns. Source: [The Soul of a New Machine](https://www.amazon.com/dp/0316491705?&linkCode=ll1&tag=kevideld-20&linkId=ec2881e22fb26c2d43de0daeebd5424d&language=en_US&ref_=as_li_ss_tl).

## Education

- [Falsehoods CS Students (Still) Believe Upon Graduating](https://www.netmeister.org/blog/cs-falsehoods.html) - A list of things (not only) computer science students tend to erroneously and at times surprisingly believe even though they (probably) should know better.
- [Postdoc myths](https://www.cs.kent.ac.uk/people/staff/srk21/blog/2019/12/02/) - “Lots of things are said, written and believed about postdoctoral researchers that are simply not true.”

## Emails

- [Falsehoods about Email](https://beesbuzz.biz/code/439-Falsehoods-programmers-believe-about-email) - On addresses, content and delivery.
- [I Knew How to Validate an Email Address Until I Read the RFC](https://haacked.com/archive/2007/08/21/i-knew-how-to-validate-an-email-address-until-i.aspx/) - Provides intricate examples that are unsuspected valid email addresses according the RFC-822.
- [So you think you can validate email addresses (FOSDEM 2018)](https://fosdem.org/2018/schedule/event/email_address_quiz/) - Presentation of edge-case email addresses and why you should not use regex to parse them.
- [Your E-Mail Validation Logic is Wrong](https://www.netmeister.org/blog/email.html) - A summary of the various, surprising things that are allowed in an email address.

## Geography

- [Falsehoods about Geography](https://wiesmann.codiferes.net/wordpress/archives/15187) - Takes on places, their names and locations.
- [Falsehoods about Maps](http://www.atlefren.net/post/2014/09/falsehoods-programmers-believe-about-maps/) - Covers coordinates, projection and GIS.
- [I Hate Coordinate Systems](https://ihatecoordinatesystems.com) - A guide for geospatial practitioners on diagnosing and fixing common issues with coordinate systems.
- [Top 5 most insane kanji place names in Japan](https://web.archive.org/web/20210310050932/https://soranews24.com/2016/12/01/w-t-f-japan-top-5-most-insane-kanji-place-names-in-japan%E3%80%90weird-top-five%E3%80%91/) - “There's one special group of kanji that's hard even for Japanese people to read: place names.”

## Human Identity

- [Falsehoods about Names](https://www.kalzumeus.com/2010/06/17/falsehoods-programmers-believe-about-names/) - The article that started it all.
- [Falsehoods about Names – With Examples](https://shinesolutions.com/2018/01/08/falsehoods-programmers-believe-about-names-with-examples/) - A revisited version of the article above, this time with detailed explanations.
- [Falsehoods about Biometrics](https://shkspr.mobi/blog/2021/01/falsehoods-programmers-believe-about-biometrics/) - Fingerprints are not unique.
- [Falsehoods about Families](https://shkspr.mobi/blog/2017/03/falsehoods-programmers-believe-about-families/) - You can't really define a family with strict rules.
- Falsehoods about Gender: [#1](https://gist.github.com/garbados/f82604ea639e0e47bf44) & [#2](https://medium.com/gender-2-0/falsehoods-programmers-believe-about-gender-f9a3512b4c9c) - Gender is part of human identity and has its own subtleties.
- [Falsehoods about Me](https://skylarmacdonald.com/falsehoods/) - Issues at the intersection of names and gender and internationalization.
- [Gay Marriage: The Database Engineering Perspective](https://web.archive.org/web/20170914014648/https://qntm.org/gay) - How to store a marriage in a database while addressing most of the falsehoods about gender, naming and relationships.
- [Personal Names Around the World](https://www.w3.org/International/questions/qa-personal-names) - How do people's names differ around the world, and what are the implications for the Web?
- [XKCD #327: Exploits of a Mom](https://xkcd.com/327/) - Funny take on how implementation of a falsehood might lead to security holes.
- [Hello, I'm Mr. Null. My Name Makes Me Invisible to Computers](https://www.wired.com/2015/11/null/) - Real-life example on how implemented falsehood has negative impact on someone's life.
- [HL7 v3 RIM](https://www.hl7.org/implement/standards/product_brief.cfm?product_id=186) - A flexible data model for representing human names.
- [Apple iOS `NSPersonNameComponentsFormatter`](https://developer.apple.com/library/ios/documentation/Miscellaneous/Reference/NSPersonNameComponentsFormatter_Class/index.html) - Localized representations of the components of a person's name.

## Internationalization

On character encoding, string formatting, unicode and internationalization.

- [Falsehoods about Language](http://garbled.benhamill.com/2017/04/18/falsehoods-programmers-believe-about-language) - Translating a software from English is not as straightforward as it seems to be.
- [Falsehoods about Plain Text](https://jeremyhussell.blogspot.com/2017/11/falsehoods-programmers-believe-about.html#main) - Plain text can't cut it, which makes Unicode even more incredible for its ability to just work well.
- [Falsehoods about text](https://wiesmann.codiferes.net/wordpress/archives/30296) - A subset of the falsehoods from above, illustrated with some examples.
- [Internationalis(z)ing Code](https://www.youtube.com/watch?v=0j74jcxSunY) - A video about things you need to keep in mind when internationalizing your code.
- [Minimum to Know About Unicode and Character Sets](https://www.joelonsoftware.com/2003/10/08/the-absolute-minimum-every-software-developer-absolutely-positively-must-know-about-unicode-and-character-sets-no-excuses/) - A good introduction to unicode, its historical context and origins, followed by an overview of its inner working.
- [Awesome Unicode](https://github.com/Wisdom/Awesome-Unicode) - A curated list of delightful Unicode tidbits, packages and resources.
- [Dark corners of Unicode](https://eev.ee/blog/2015/09/12/dark-corners-of-unicode/) - Unicode is extensive, here be dragons.
- [Let's Stop Ascribing Meaning to Code Points](https://manishearth.github.io/blog/2017/01/14/stop-ascribing-meaning-to-unicode-code-points/) - Dives deeper in Unicode and dispels myths about code points.
- [Breaking Our `Latin-1` Assumptions](https://manishearth.github.io/blog/2017/01/15/breaking-our-latin-1-assumptions/) - Most programmers spend so much time with `Latin-1` they forgets about other's scripts quirks.
- [Ode to a shipping label](http://i.imgur.com/4J7Il0m.jpg) - Character encoding is hard, more so when each broken layer of data input adds its own spice.
- [i18n Testing Data](https://github.com/patch/i18n-testing) - Compilation of real-word international and diverse name data for unit testing and QA.
- [Big List of Naughty Strings](https://github.com/minimaxir/big-list-of-naughty-strings) - A huge corpus of strings which have a high probability of causing issues when used as user-input data. A must have set of practical edge-cases to test your software against.

## Management

- [Falsehoods about Job Applicants](https://web.archive.org/web/20170114022820/https://medium.com/@creatrixtiara/falsehoods-programmers-believe-about-job-applicants-99280437c616) - Assumptions about job applicants and their job histories aren't necessarily true.

## Multimedia

- [Falsehoods about Video](https://haasn.xyz/posts/2016-12-25-falsehoods-programmers-believe-about-%5Bvideo-stuff%5D.html) - Cover it all: video decoding and playback, files, image scaling, color spaces and conversion, displays and subtitles.
- [Horrible edge cases to consider when dealing with music](https://dustri.org/b/horrible-edge-cases-to-consider-when-dealing-with-music.html) - Music catalogs data are full of crazy stuff.
- [MusicBrainz database schema](https://musicbrainz.org/doc/MusicBrainz_Database/Schema) - An open-source project and database that seems to have solved the complexity of music catalog management.
- [DDEX](https://ddex.net/standards/) - The industry standard for music metadata, including archiving, sound recording, sales and usage reporting, royalties and license deals.
- [Apple Music Style Guide](https://help.apple.com/itc/musicstyleguide/en.lproj/static.html) - Quality insurance guidelines to format music, art, and metadata to increase discoverability.

## Networks

- [Falsehoods about Networks](http://blog.erratasec.com/2012/06/falsehoods-programmers-believe-about.html) - Covers TCP, DHCP, DNS, VLANs and IPv4/v6.
- [Fallacies of Distributed Computing](https://en.wikipedia.org/wiki/Fallacies_of_distributed_computing) - Assumptions that programmers new to distributed applications invariably make.
- [There's more than one way to write an IP address](https://ma.ttias.be/theres-more-than-one-way-to-write-an-ip-address/) - Some parts of the address are optional, mind the decimal and octal notations, and [don't forget IPv6](https://news.ycombinator.com/item?id=20390981) either.
- [IDN is crazy](https://daniel.haxx.se/blog/2022/12/14/idn-is-crazy/) - International characters in domain names mean support of homographs and heterographs.
- [`hostname-validate`](https://github.com/jakeogh/hostname-validate) - An attempt to validate hostnames in Python.

## Phone Numbers

- [Falsehoods about Phone Numbers](https://github.com/googlei18n/libphonenumber/blob/master/FALSEHOODS.md) - Covers phone numbers, their representation and meaning.
- [`libphonenumber`](https://github.com/googlei18n/libphonenumber) - Google's common Java, C++ and JavaScript library for parsing, formatting, and validating international phone numbers. Also available for [C#](https://github.com/twcclegg/libphonenumber-csharp), [Objective-C](https://github.com/iziz/libPhoneNumber-iOS), [Python](https://github.com/daviddrysdale/python-phonenumbers), [Ruby](https://github.com/sstephenson/global_phone) and [PHP](https://github.com/giggsey/libphonenumber-for-php).

## Postal Addresses

- [Falsehoods about Addresses](https://www.mjt.me.uk/posts/falsehoods-programmers-believe-about-addresses/) - Covers streets, postal codes, buildings, cities and countries.
- [Falsehoods about Residence](https://twitter.com/samphippen/status/813896916534784004) - It's not only about the address itself, but the relationship between a person and its residence.
- [Letter Delivered Despite No Name, No Address](https://twitter.com/loriskumo/status/735851511331356672) - Ultimate falsehood about postal addresses: you do not need one.
- [What is the Most Minimal UK Address Possible?](https://microblog.vladh.net/posts/most-minimal-uk-address/) - The trick is to rely on postcodes, which in the UK are pretty specific and “often identify one or a few specific buildings, unlike countries where a postcode represents an entire neighbourhood”.
- [The Bear with Its Own ZIP Code](https://kottke.org/19/08/the-bear-with-its-own-zip-code) - Smokey Bear has his own ZIP Code (`20252`) because he gets so much mail.
- [Why doesn't Costa Rica use real addresses?](https://www.crcdaily.com/p/why-doesnt-costa-rica-use-real-addresses) - Costa Rican uses an idiosyncratic system of addresses that relies on landmarks, history and quite a bit of guesswork.
- [Regex and Postal Addresses](https://smartystreets.com/articles/regular-expressions-for-street-addresses) - Why regular expressions and street addresses do not mix.
- [Parsing the Infamous Japanese Postal CSV](https://www.dampfkraft.com/posuto.html) - “I saw many horrors, but I've never seen this particular formatting choice anywhere else.”
- [USPS Postal Addressing Standards](https://pe.usps.com/text/pub28/welcome.htm) - Describes both standardized address formats and content.
- [`libaddressinput`](https://github.com/googlei18n/libaddressinput) - Google's common C++ and Java library for parsing, formatting, and validating international postal addresses.
- [`addressing`](https://github.com/commerceguys/addressing) - A PHP 5.4+ addressing library, powered by Google's dataset.
- [`postal-address`](https://github.com/scaleway/postal-address) - Python module to parse, normalize and render postal addresses.
- [`address`](https://github.com/Boostport/address) - Go library to validate and format addresses using Google's dataset.

## Science

- [Falsehoods about Systems of Measurement](https://www.stevemoser.org/posts/dev/falsehoods-programmers-believe-about-systems-of-measurement.html) - On working with systems of measurement and converting between them.

## Society

- [Falsehoods about Political Appointments](https://twitter.com/oliver_dw/status/737930439575404544) - Designing election systems has its own tricks.
- [Falsehoods about Women In Tech](https://gist.github.com/Su-Shee/5d1a417fa9de19c15477) - Myth about women in STEM (Science, Technology, Engineering, Math) industries.

## Software Engineering

- [Falsehoods about Versions](https://github.com/xenoterracide/falsehoods/blob/master/versions.md) - Attributing an identity to a software release might be harder than thought.
- [Falsehoods about Build Systems](https://pozorvlak.livejournal.com/174763.html) - Building software is hard. Building software that builds software is harder.
- [Falsehoods about Undefined Behavior](https://predr.ag/blog/falsehoods-programmers-believe-about-undefined-behavior/) - Invoking undefined behavior can cause *anything* to happen, for a much broader definition of "anything" than one might think.
- [Falsehoods about CSVs](https://donatstudios.com/Falsehoods-Programmers-Believe-About-CSVs) - While RFC4180 to exists, it is far from definitive and goes largely ignored.
- [Falsehoods about Package Managers](https://kdeldycke.github.io/meta-package-manager/falsehoods.html) - Covers package and their managers.
- [Falsehoods about Testing](https://club.ministryoftesting.com/t/falsehoods-testers-believe/1371) - An attempt to establish a list of falsehoods about testing.
- [Falsehoods about Search](https://opensourceconnections.com/blog/2019/05/29/falsehoods-programmers-believe-about-search/) - Why search (including analysis, tokenization, highlighting) is deceptively complex.
- [What every software engineer should know about search](https://scribe.rip/p/what-every-software-engineer-should-know-about-search-27d1df99f80d) - A better sourced article on the difficulty of implementing search engines.
- [Falsehoods about Pagination](https://www.hezmatt.org/~mpalmer/blog/2018/12/12/falsehoods-programmers-believe-about-pagination.html) - Why your pagination algorithm is giving someone (possibly you) a headache.
- [Falsehoods about garbage collection](https://paul.bone.id.au/blog/2018/10/19/gc-falsehoods/) - Misconceptions about the predictability and performance of garbage collection.
- [Myths about File Paths](https://yakking.branchable.com/posts/falsehoods-programmers-believe-about-file-paths/) - Diversity of file-systems and OSes makes file paths a little harder than we might think of.
- [The weird world of Windows file paths](https://www.fileside.app/blog/2023-03-17_windows-file-paths/) - “On any Unix-derived system, a path is an admirably simple thing: if it starts with a `/`, it's a path. Not so on Windows.”
- [Myths about CPU Caches](https://software.rajivprab.com/2018/04/29/myths-programmers-believe-about-cpu-caches/) - Misconceptions about caches often lead to false assertions, especially when it comes to concurrency and race conditions.
- [Myths about `/dev/urandom`](https://www.2uo.de/myths-about-urandom) - There are a few things about `/dev/urandom` and `/dev/random` that are repeated again and again. Still they are false.
- [Facts about State Machines](https://github.com/cpressey/Facts-about-State-Machines) - State machines are often misunderstood and under-applied.
- [Hi! My name is…](https://www.youtube.com/watch?v=NIebelIpdYk) - This talk could have been named *falsehoods about usernames (and other identifiers)*.
- [Popular misconceptions about `mtime`](https://apenwarr.ca/log/20181113) - Part of a post on why file's `mtime` comparison could be considered harmful.
- [Rules for Autocomplete](http://jeremymikkola.com/posts/2019_03_19_rules_for_autocomplete.html) - Not falsehoods *per se*, but still a great list of good practices to implement autocompletion.
- [Floating Point Math](https://0.30000000000000004.com) - “Your language isn't broken, it's doing floating point math. (…) This is why, more often than not, `0.1 + 0.2 != 0.3`.”
- [The yaml document from hell](https://ruudvanasseldonk.com/2023/01/11/the-yaml-document-from-hell) - YAML is full of obscure complexity like accidental numbers and non-string keys.
- [I am endlessly fascinated with content tagging systems](https://twitter.com/hillelogram/status/1534301374166474752) - There are edge-cases even in tagging systems which are suposed to be barebone.
- [Falsehoods about Quantum Technology](https://github.com/gottfriedsz/falsehoods-quantum) - Common misconceptions about quantum technology and computers.

## Transportation

- [Falsehoods about Cars](https://github.com/driveto/falsehoods-about-cars) - Even something as common as defining a car is full of pitfalls.
- [Falsehoods about Airline Seat Maps](https://duffel.com/blog/falsehoods-about-seat-maps) - Airline seat maps are far more complex than just neat rows and columns of seats.
- [The Maddening Mess of Airport Codes](https://www.youtube.com/watch?v=jfOUVYQnuhw) - Having multiple international and national agencies trying to reconcile history, practicality and logistics makes codes follow arcane rules.
- [My name causes an issue with any booking!](https://travel.stackexchange.com/questions/149323/my-name-causes-an-issue-with-any-booking-names-end-with-mr-and-mrs) - Old airline reservation systems considers the `MR` suffix as `Mister` and drops it.

## Typography

- [Falsehoods about Fonts](https://github.com/RoelN/Font-Falsehoods) - Assumptions about typography on the web and in desktop applications.
- [Truths programmers should know about case](https://www.b-list.org/weblog/2018/nov/26/case/) - A complete reverse of the falsehoods format, on the topic of case (as in uppercase and lowercase text).

## Video Games

- [The Door Problem](https://lizengland.com/blog/2014/04/the-door-problem/) - All the things you have not considered implementing for your doors in games.

## Web

- [Falsehoods about REST APIs](https://web.archive.org/web/20201112010147/http://slinkp.com/falsehoods-programmers-believe-about-apis.html) - Pitfalls to be mindful of when creating and documenting APIs.
- [URLs: It's complicated…](https://www.netmeister.org/blog/urls.html) - There's a lot of components in an URL, and all have their own logic.
- [The Hidden Complexity of Downloading Favicons, Told in 15+ Edge Cases](https://www.simplecto.com/complexity-downloading-favicons-told-in-15-plus-edge-cases/) - Downloading that little icon you see in you browser tabs should be a simple exercise. It turned out to be a lot more complicated than you think. Be vigilant that you are not shaving a Yak.

## Contributing

Your contributions are always welcome! Please take a look at the [contribution guidelines](https://github.com/kdeldycke/awesome-falsehood/blob/main/.github/contributing.md) first.

## Footnotes

This list gathered some popularity in social medias over the past few years. See it being [discussed and mentioned elsewhere](https://github.com/kdeldycke/kdeldycke/blob/main/in-the-media.md).

The [header image](https://github.com/kdeldycke/awesome-falsehood/blob/main/assets/awesome-falsehood-header.jpg) is based on a modified [photo taken in February 2010 by Iza Bella](https://commons.wikimedia.org/wiki/File:BLW_Truth_and_Falsehood.jpg), distributed under a [Creative Commons BY-SA 2.0 UK license](https://creativecommons.org/licenses/by-sa/2.0/uk/deed.en).

\[1\]: [*Notebooks, 1914-1916*](https://www.amazon.com/dp/1324090804?&linkCode=ll1&tag=kevideld-20&linkId=a1903c3fbfdc82fbe2e566fca40718fb&language=en_US&ref_=as_li_ss_tl) (Liveright, 2022) - [source: page 14e](https://archive.org/details/notebooks191419100witt/page/n35). [\[↑\]](#intro-quote-ref)


text:
# Contributor Covenant Code of Conduct

## Our Pledge

In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, gender identity and expression, level of experience,
nationality, personal appearance, race, religion, or sexual identity and
orientation.

## Our Standards

Examples of behavior that contributes to creating a positive environment
include:

- Using welcoming and inclusive language
- Being respectful of differing viewpoints and experiences
- Gracefully accepting constructive criticism
- Focusing on what is best for the community
- Showing empathy towards other community members

Examples of unacceptable behavior by participants include:

- The use of sexualized language or imagery and unwelcome sexual attention or
  advances
- Trolling, insulting/derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or electronic
  address, without explicit permission
- Other conduct which could reasonably be considered inappropriate in a
  professional setting

## Our Responsibilities

Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.

Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.

## Scope

This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.

## Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at <kevin@deldycke.com>. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.

Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.

## Attribution

This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at [https://contributor-covenant.org/version/1/4][version]

[homepage]: https://contributor-covenant.org
[version]: https://contributor-covenant.org/version/1/4/


text:
---
github: kdeldycke


text:
# https://docs.github.com/en/github/administering-a-repository
# /configuration-options-for-dependency-updates
---
version: 2
updates:

  - package-ecosystem: "github-actions"
    directory: "/"
    schedule:
      interval: "daily"
    labels:
      - "📦 dependencies"
    assignees:
      - "kdeldycke"


text:
# Contributing

Your contributions are always welcome! Here are some guidelines.

## Good Candidates

Before contributing, make sure the new link you'd like to add is a good
candidate.

Here is a non-restrictive list of items which are good candidates for inclusion
in this awesome list.

### Falsehood Articles

Articles following the *falsehood* schema are prime candidates for inclusion in
this awesome list.

These articles starts with the hypothesis that developers have a naive and
simple view of a domain. Then proceed to list a set of candid assumptions that
might be held by programmers. Each one is intentionally false, and in their
best form are illustrated with a counter-example.

A list of falsehood is crafted as a progression that is designed to refine
concepts. Having read the whole list of falsehood, the reader should possess a
better overview of a domain while dispelling its myths, point out common
pitfalls and demonstrate its subtleties.

*falsehood* articles are, in a sense, a suite of wordy unit-tests covering
extensive edge-cases provided by real-world usage. The world is messy.
Discovering a domain to be much more complex than anticipated will lead to
frustrations. And cause flipping tables `(╯°□°)╯︵ ┻━┻`. This is the sign of a
great candidate for that list!

Articles featuring items that are applicable to one product (or a service) and
one only can't be considered as generic enough and should be avoided.

### Libraries

Programming libraries or modules are good candidates too, if they solve or
reduce the complexities pointed to by *falsehood* articles above.

That way we can put back tables in place. `┬─┬ ノ( ゜-゜ノ)`

### Data Structures

Data models and structures generic enough to cover and address most of the
falsehoods are also welcome in this page.

## Pull-Request and Issue

- Search past and current issues and pull-requests for previous suggestions before making a new one, as yours may be a duplicate or a work in progress.

- Only one list item per commit.

- Only one commit per pull-request. Always squash commits after applying changes.

- Check your spelling and grammar.

- Add the reason why the linked resource is awesome. And what it adds to existing content.

## Linting

Have your pull-request pass the [official Awesome List's linter](https://github.com/sindresorhus/awesome-lint).

No extra work is required here as it is [already integrated by the way of GitHub actions](https://github.com/kdeldycke/awesome-falsehood/tree/main/.github/workflows).

To run the linter locally, do:

```shell-session
$ npm i npx
$ npx awesome-lint
```

## Formatting

Additional rules not covered by `awesome-lint`, to keep the content clean and tidy.

If one of these rule conflict with the linter, the linter's rule should takes precedence. Apply it.

### General content

- Remove any trailing whitespaces.

- Use spaces, no tabs, for indention.

- Apostrophes should be using the single ASCII mark: `'`.

- Try to quote the original content as-is to summarize the point of the linked content.

- If a straight quote doesn't cut it, feel free to paraphrase both the item's title and description. Remember, this is curation: we are increasing the value of the original content by aggregation and categorization, yes, but also by smart editorializing. As long as you respect the spirit of the original content it's OK.

### Sections

- Sections are in alphabetical order, as all topics are independent from each others.

- Section might feature one paragraph introduction and a figure (graph, drawing, photo).

### Item title

- Link title must be stripped out of the "*Programmers believe*" part to keep it compact.

- URL must use HTTPs protocol if available.

- No `“` and `”` curved quotation marks. This is reserved for original content quotation in descriptions.

- To quote, use either the single or double variations: `'` and `"`. Keep them properly balanced.

### Item description

- Quotes should be properly delimited with the `“` and `”` curved quotation marks.

- You can reduce the original text by using an ellipsis in parenthesis `(…)`.

- For quoting inside a quote, use single or double `'` and `"` ASCII marks. Keep them properly balanced.

- To serialize a list into a description, use the following format:

  > This is my own description. Here is a list quoted from the original content about **“a random subject: 1. Blah blah blah; 2. Blah blah blah? 3. Blah blah blah.”** This makes sense right?

  This provides visual anchor points that help readability and quick content scanning.

  - You can skip some items from the original list and renumber it.

  - You shouldn't have to re-order it though.

- An additional link in the description is allowed. This must be limited to some rare cases. Like pointing to a bigger concept, an acronym definition, or reference material (book, biography, …).

### CLI helpers

One-liners to fix-up some common formatting mistakes. Use with great caution and always double-check and edit the results.

- Replaces star list item markers by dashes:

  ```shell-session
  $ sed -i 's/^* /- /g' ./README.md
  ```

- Replaces typographic quotes with ASCII ones:

  ```shell-session
  $ sed -i "s/‘/\'/g" ./readme.md
  $ sed -i "s/’/\'/g" ./readme.md
  ```

- Forces quotes to end with a dot:

  ```shell-session
  $ sed -i 's/`$/`\./g' ./readme.md
  ```


text:
### Motivation

<!--

Explain the motivation for adding this link to the current collection. What's special about it?

Note: you can skip this section if you're proposing something as trivial as fixing a typo.

-->

This new link is special because...

### Affiliation

<!-- Please indicate how you are associated with the new proposed content: -->

- [ ] I am the author of the article or project
- [ ] I am working for/with the company which is publishing the article or project
- [ ] I'm just a rando who stumbled upon this via social networks

### Self checks

- [ ] I have [read the Code of Conduct](https://github.com/kdeldycke/awesome-falsehood/blob/main/.github/code-of-conduct.md)
- [ ] I applied all rules from the [Contributing guide](https://github.com/kdeldycke/awesome-falsehood/blob/main/.github/contributing.md)
- [ ] I have checked there is no other [Issues](https://github.com/kdeldycke/awesome-falsehood/issues) or [Pull Requests](https://github.com/kdeldycke/awesome-falsehood/pulls) covering the same topic to open


text:
name: Add new link
description: You would like to add a new link to the collection
labels: ["🆕 new link"]
body:

  - type: input
    id: link
    attributes:
      label: URL of the article or project
    validations:
      required: true

  - type: textarea
    id: motivation
    attributes:
      label: Motivation
      description: >
        Explain the motivation for adding this link to the current collection. What's special about it?
      placeholder: |
        This new link is special because...
    validations:
      required: true

  - type: checkboxes
    id: affiliation
    attributes:
      label: Affiliation
      description: >
        Please indicate how you are associated with the new proposed content.
      options:
        - label: "I am the author of the article or project"
        - label: "I am working for/with the company which is publishing the article or project"
        - label: "I'm just a rando who stumbled upon this via social networks"
    validations:
      required: true

  - type: checkboxes
    id: self-checks
    attributes:
      label: Self checks
      options:
        - label: >
            I have [read the Code of
            Conduct](https://github.com/kdeldycke/awesome-falsehood/blob/main/.github/code-of-conduct.md)
        - label: >
            I applied all rules from the [Contributing
            guide](https://github.com/kdeldycke/awesome-falsehood/blob/main/.github/contributing.md)
        - label: >
            I have checked there is no other [Issues](https://github.com/kdeldycke/awesome-falsehood/issues) or [Pull
            Requests](https://github.com/kdeldycke/awesome-falsehood/pulls) covering the same topic to open
    validations:
      required: true


text:
---
name: Label sponsors
"on":
  pull_request:
    types:
      - opened
  issues:
    types:
      - opened

jobs:

  label-sponsors:
    uses: kdeldycke/workflows/.github/workflows/label-sponsors.yaml@v2.17.4


text:
---
name: Autolock
"on":
  schedule:
    # Run weekly, every Monday at 8:43.
    - cron: "43 8 * * 1"

jobs:

  autolock:
    uses: kdeldycke/workflows/.github/workflows/autolock.yaml@v2.17.4


text:
---
name: Lint
"on":
  push:

jobs:

  lint:
    uses: kdeldycke/workflows/.github/workflows/lint.yaml@v2.17.4


text:
---
name: Labels
"on":
  push:
    branches:
      - main

jobs:

  labels:
    uses: kdeldycke/workflows/.github/workflows/labels.yaml@v2.17.4


text:
---
name: Docs
"on":
  push:
    # Only targets main branch to avoid amplification effects of auto-fixing
    # the exact same stuff in multiple non-rebased branches.
    branches:
      - main

jobs:

  docs:
    uses: kdeldycke/workflows/.github/workflows/docs.yaml@v2.17.4


text:
---
name: Autofix
"on":
  push:
    # Only targets main branch to avoid amplification effects of auto-fixing
    # the exact same stuff in multiple non-rebased branches.
    branches:
      - main

jobs:

  autofix:
    uses: kdeldycke/workflows/.github/workflows/autofix.yaml@v2.17.4


text:
Logitech® Z906 Surround Sound Speakers
======================================

Overview
--------

5.1 surround sound speaker system with the amplifier built into the subwoofer
and managed by an external control console attached using a
`DE-15 <https://en.wikipedia.org/wiki/D-subminiature>`_ connector.

Purpose
-------

Provide unofficial documentation of the serial protocol and possible
firmware/configuration modifications.

The console `firmware <firmware.rst>`_ can be modified to:

* Automatically turn the speakers on when power is supplied.
* Change the automatic standby idle timeout from the default 2 hours.

Automatic standby
~~~~~~~~~~~~~~~~~

To enable/disable automatic standby, hold the "level" button for 5 seconds
(until the level change light goes out). There's no obvious indication that
anything has changed but the stored effects for all of the inputs will have been
reordered because the console sends them in the wrong order (check by turning
the console off and on).

To get this into a known state (automatic standby enabled), hold down the
"input" button for 8 seconds while in standby. This will reset all settings.

Contents
--------

* `Firmware <firmware.rst>`_
* `Interface <interface.rst>`_
* `Protocol <protocol.rst>`_

"Logitech" is a trademark of `Logitech International SA <https://www.logitech.com/>`_.


text:
Interface
=========

The control console and the amplifier are connected by a cable that uses a
`DE-15 <https://en.wikipedia.org/wiki/D-subminiature>`_ connector. This can be
extended with a `VGA <https://en.wikipedia.org/wiki/VGA_connector>`_ extension
cable (but the screws to hold the connectors together will be mismatched).

When a VGA cable is used, pin 9 may not be present.

Pin out
-------

+-----+-----------------------------+-------------------------------------------------+
| Pin | Console                     | Amplifier                                       |
+=====+=============================+=================================================+
|   1 |                             | Headphones Right                                |
+-----+-----------------------------+-------------------------------------------------+
|   2 |                             | Headphones Left                                 |
+-----+-----------------------------+-------------------------------------------------+
|   3 | Audio Ground                | Audio Ground                                    |
+-----+-----------------------------+-------------------------------------------------+
|   4 | Aux Right                   |                                                 |
+-----+-----------------------------+-------------------------------------------------+
|   5 | Aux Left                    |                                                 |
+-----+-----------------------------+-------------------------------------------------+
|   6 | Ground                      | Ground                                          |
+-----+-----------------------------+-------------------------------------------------+
|   7 | Unknown (not required)      | Unknown (not required)                          |
+-----+-----------------------------+-------------------------------------------------+
|   8 | | Pull-down (0V) resistor   | | Output 3.3V for 500ms at power up/comms start |
|     | | Amplifier presence        | | Output 3.3V for 100ms after comms stop        |
+-----+-----------------------------+-------------------------------------------------+
|   9 | Output 3.3V when powered    |                                                 |
|     | (not required)              | Unused                                          |
+-----+-----------------------------+-------------------------------------------------+
|  10 | Unknown (not required)      | Unused                                          |
+-----+-----------------------------+-------------------------------------------------+
|  11 | Power supply                | 3.3V                                            |
+-----+-----------------------------+-------------------------------------------------+
|  12 | Rx                          | Tx                                              |
+-----+-----------------------------+-------------------------------------------------+
|  13 | Tx                          | Rx                                              |
+-----+-----------------------------+-------------------------------------------------+
|  14 | Unused                      | Unused                                          |
+-----+-----------------------------+-------------------------------------------------+
|  15 | | Output 0V if comms active | | Pull-up (3.3V) resistor                       |
|     | |                           | | Console presence                              |
+-----+-----------------------------+-------------------------------------------------+

Pin 7 has some bidirectional signalling with intervals of no less than 100ms
related to changes in the values of pins 8 and 15. If it's connected then the
duration of amplifier pin 8 changes to 1s at power up/comms start and 4s after
comms stop.

Serial communication
--------------------

The Rx/Tx pins are 3.3V TTL serial at a baud rate of 57600 bps with 8 bits per
byte, odd parity and 1 stop bit. All communication is initiated by the console.

The amplifier will not turn on its power to the speakers until the console is
present. It will turn off its power immediately if there is no console present.
The power supply for the console is always active.

The console will get upset if the amplifier doesn't respond to communication
(this is the cause of the 2, 3 or 4 error indication displayed on the console
input selection LEDs).

* 2 LEDs: amplifier presence remains 3.3V high
* 3 LEDs: no response to serial communication

The `protocol <protocol.rst>`_ is a simple binary interface.


text:
Firmware
========

Control Console
---------------

The microcontroller in the control console is an STM8S103K3. The programming
header is at the bottom of the PCB to the right of the microcontroller.

.. figure:: console-pcb.jpg
   :height: 275px
   :alt: Console PCB with "PROGRAMMING" header at the bottom (2 rows of 3 pins)

   Programming header pins

Older versions will have a programming port that can be used without opening
the control console. If it is not present you will need to open the console - be
careful not to insert anything deep between the front panel and the PCB as this
may damage the lower buttons.

.. figure:: console-programming-port.jpg
   :height: 275px
   :alt: Console with programming port opened (2 rows of 3 pins)

   Programming port pins

   +---------------------------+--------------------+--------------------+
   | ○ No connection           | ○ SWIM (pin 26)    | ○ NRST (pin 1)     |
   +---------------------------+--------------------+--------------------+
   | ■ |Vdd| (pin 6) 3.3V      | ○ GND (pin 4)      | ○ GND (pin 4)      |
   +---------------------------+--------------------+--------------------+

   The bottom row of pins on the programming port is the row nearest the PCB.
.. |Vdd| replace:: V\ :sub:`DD`

The firmware can be accessed using an ST-LINK implementation,
e.g. `esp-stlink <https://github.com/nomis/esp-stlink/tree/sa>`_
and `stm8flash <https://github.com/nomis/stm8flash/tree/sa>`_.

The flash consists of 64 byte pages. Writes must be to whole pages.

The EEPROM consists of 640 bytes that are all zero.

Attempts were made to use an official ST-LINK/V2 but it was unable to
communicate.

.. list-table::
   :header-rows: 1

   * - Version
     - Size
     - SHA-3-256 hash
   * - S-00103 (2016-2020)
     - 8KB
     - ``a16ecffacc67c9005814028080c90d098f10708b88b285fdbeef480358c37cb8``

Useful tools
~~~~~~~~~~~~

* `Disassembler (naken_asm) <https://github.com/mikeakohn/naken_asm>`_
* `Decompiler (Ghidra) <https://ghidra-sre.org/>`_
  with `STM8 plugin <https://github.com/esaulenka/ghidra_STM8>`_

Modifications
~~~~~~~~~~~~~

Idle time for automatic standby
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Read 64 bytes of flash at ``0x80C0`` and modify the seconds time value
(U32BE, default 7198) at ``0x80DE``:

.. code-block:: none

   80C0  xx xx xx xx xx xx xx xx  xx xx xx xx xx xx xx xx
   80D0  xx xx xx xx xx xx xx xx  xx xx xx xx xx xx 00 00
                                                    ↑↑ ↑↑
         ↓↓ ↓↓
   80E0  1C 1E xx xx xx xx xx xx  xx xx xx xx xx xx xx xx
   80F0  xx xx xx xx xx xx xx xx  xx xx xx xx xx xx xx xx

Write 64 bytes of flash at ``0x80C0`` (2 hours):

.. code-block:: none

   80C0  xx xx xx xx xx xx xx xx  xx xx xx xx xx xx xx xx
   80D0  xx xx xx xx xx xx xx xx  xx xx xx xx xx xx 00 00
                                                    ↑↑ ↑↑
         ↓↓ ↓↓
   80E0  1C 20 xx xx xx xx xx xx  xx xx xx xx xx xx xx xx
   80F0  xx xx xx xx xx xx xx xx  xx xx xx xx xx xx xx xx

Write 64 bytes of flash at ``0x80C0`` (24 hours):

.. code-block:: none

   80C0  xx xx xx xx xx xx xx xx  xx xx xx xx xx xx xx xx
   80D0  xx xx xx xx xx xx xx xx  xx xx xx xx xx xx 00 01
                                                    ↑↑ ↑↑
         ↓↓ ↓↓
   80E0  51 80 xx xx xx xx xx xx  xx xx xx xx xx xx xx xx
   80F0  xx xx xx xx xx xx xx xx  xx xx xx xx xx xx xx xx

Write 64 bytes of flash at ``0x80C0`` (7 days):

.. code-block:: none

   80C0  xx xx xx xx xx xx xx xx  xx xx xx xx xx xx xx xx
   80D0  xx xx xx xx xx xx xx xx  xx xx xx xx xx xx 00 09
                                                    ↑↑ ↑↑
         ↓↓ ↓↓
   80E0  3A 80 xx xx xx xx xx xx  xx xx xx xx xx xx xx xx
   80F0  xx xx xx xx xx xx xx xx  xx xx xx xx xx xx xx xx

Write 64 bytes of flash at ``0x80C0`` (no auto off):

.. code-block:: none

   80C0  xx xx xx xx xx xx xx xx  xx xx xx xx xx xx xx xx
   80D0  xx xx xx xx xx xx xx xx  xx xx xx xx xx xx 01 00
                                                    ↑↑ ↑↑
         ↓↓ ↓↓
   80E0  00 00 xx xx xx xx xx xx  xx xx xx xx xx xx xx xx
   80F0  xx xx xx xx xx xx xx xx  xx xx xx xx xx xx xx xx

This value is limited to 24 bits by the protocol, so setting any bits in the top
byte will cause the idle time to never be exceeded.

Automatic power on
^^^^^^^^^^^^^^^^^^
This code is part of the reset interrupt for the microcontroller so it will not
be executed after a short power cycle while the speakers are turned off.

When turning the speakers on/off by switching the power supply on/off, be aware
that the settings (current volume, etc.) are only saved when going into standby.

There is a `protocol <protocol.rst>`_ side effect of enabling this in that the
console will send ``F8`` or ``FC`` instead of ``34`` the first time it goes into
standby. This appears to have no impact to the operation of the speakers.

Read 64 bytes of flash at ``0x87C0`` and modify the instruction at ``0x87F2``:

.. code-block:: none

   87C0  xx xx xx xx xx xx xx xx  xx xx xx xx xx xx xx xx
   87D0  xx xx xx xx xx xx xx xx  xx xx xx xx xx xx xx xx
   87E0  xx xx xx xx xx xx xx xx  xx xx xx xx xx xx CD 89
   87F0  BD 9A 4F CD 85 D1 xx xx  xx xx xx xx xx xx xx xx
               ↑↑

Write 64 bytes of flash at ``0x87C0`` (auto on):

.. code-block:: none

   87C0  xx xx xx xx xx xx xx xx  xx xx xx xx xx xx xx xx
   87D0  xx xx xx xx xx xx xx xx  xx xx xx xx xx xx xx xx
   87E0  xx xx xx xx xx xx xx xx  xx xx xx xx xx xx CD 89
   87F0  BD 9A 9D CD 85 D1 xx xx  xx xx xx xx xx xx xx xx
               ↑↑

Write 64 bytes of flash at ``0x87C0`` (power up in standby):

.. code-block:: none

   87C0  xx xx xx xx xx xx xx xx  xx xx xx xx xx xx xx xx
   87D0  xx xx xx xx xx xx xx xx  xx xx xx xx xx xx xx xx
   87E0  xx xx xx xx xx xx xx xx  xx xx xx xx xx xx CD 89
   87F0  BD 9A 4F CD 85 D1 xx xx  xx xx xx xx xx xx xx xx
               ↑↑

Explanation:
  The original instruction clears register A which is the parameter to the
  function at ``0x85D1``. By not clearing it, the previous function that was
  called (``0x89BD``) has left A with a non-zero value.

  Function ``0x85D1`` stores the value at memory ``0x01BB``, which is then used
  in the first status request to decide whether to run the power on or power off
  function.


text:
Protocol
========

All commands are initiated by the console. All state is maintained primarily by
the amplifier so the console requires the echoed responses to update its state.

There is no way to do automatic power on without modifying the
`firmware <firmware.rst>`_. It is not otherwise possible to make the console
light up and respond to input unless it is powered on through its own power
button or remote control.

Message formats
---------------

All messages are one byte except for ``AA`` that starts a longer message.

The longer messages have the following format:

.. code-block:: none

   AA <U8 type> <U8 length of data> <variable length data> <U8 checksum>

The checksum is verified by calculating the U8 sum of all bytes from the type
(inclusive) to the checksum (inclusive) so that the final result is 0.

Communication is represented as follows:

.. code-block:: none

   > Message from console to amplifier
   < Message from amplifier to console

Do not send additional requests to the amplifier while it is/will be sending a
multi-byte response. It cannot handle this and will overwrite part of the output
with any new single byte responses. For multi-byte responses it will start again
instead of finishing the earlier response. Wait for it to finish responding
before making additional requests. The console does not have this problem.

Status commands
---------------

Read status/configuration
~~~~~~~~~~~~~~~~~~~~~~~~~

.. code-block:: none

   > 34
   < AA
   < 0A = type
   < 14 = length of remaining data (excluding checksum)
   < 0A = main volume (0 to 43)
   < 15 = rear level (0 to 43)
   < 15 = centre level (0 to 43)
   < 15 = subwoofer level (0 to 43)
   < 00 = input (0 to 5 => 1 to 6)
   < 00 = mute (0 = off, 1 = on)
   < 00 = input 4 effect (0 = 3D, 1 = 2.1, 2 = 4.1, 3 = disabled)
   < 00 = input 5 effect (0 = 3D, 1 = 2.1, 2 = 4.1, 3 = disabled)
   < 00 = input 2 effect (0 = 3D, 1 = 2.1, 2 = 4.1, 3 = disabled)
   < 00 = input 6 effect (0 = 3D, 1 = 2.1, 2 = 4.1, 3 = disabled)
   < 03 = input 1 effect (0 = 3D, 1 = 2.1, 2 = 4.1, 3 = disabled)
   < 00 = input 3 effect (0 = 3D, 1 = 2.1, 2 = 4.1, 3 = disabled)
   < 00 = digital signal status (amplifier)
   < 00
   < 01
   < 05
   < 04
   < 00 = standby (0 = on, 1 = standby)
   < 00
   < 00 = auto standby (0 = enabled, 1 = disabled)
   < XX = checksum

This can also be used in reverse, to get the status from the console. The
console reports the input effects in ascending order 1-6 (and only if they have
been set using the console). Allowing the response to go to the amplifier will
overwrite the effect settings with incorrect values and the current idle time
will become over 24 days which would normally result in an automatic standby
occurring. It will also overwrite the digital signal status with the console's
value until it next changes.

.. code-block:: none

   > 34
   > AA
   > 0E = type
   > 03 = length of remaining data (excluding checksum)
   > 20 = set most significant byte of the idle time (lower bytes are reset to 0)
   > 00
   > 00
   > CF = checksum
   < AA
   < 0A = type
   < 14 = length of remaining data (excluding checksum)
   < 0A = main volume (0 to 43)
   < 15 = rear level (0 to 43)
   < 15 = centre level (0 to 43)
   < 15 = subwoofer level (0 to 43)
   < 00 = input (0 to 5 => 1 to 6)
   < 00 = mute (0 = off, 1 = on)
   < 00 = input 1 effect (0 = 3D, 1 = 2.1, 2 = 4.1, 3 = disabled)
   < 00 = input 2 effect (0 = 3D, 1 = 2.1, 2 = 4.1, 3 = disabled)
   < 00 = input 3 effect (0 = 3D, 1 = 2.1, 2 = 4.1, 3 = disabled)
   < 00 = input 4 effect (0 = 3D, 1 = 2.1, 2 = 4.1, 3 = disabled)
   < 00 = input 5 effect (0 = 3D, 1 = 2.1, 2 = 4.1, 3 = disabled)
   < 00 = input 6 effect (0 = 3D, 1 = 2.1, 2 = 4.1, 3 = disabled)
   < 00 = digital signal status (console)
   < 00
   < 06
   < 01
   < 03
   < 00 = standby (0 = on, 1 = standby)
   < 00
   < 00 = auto standby (0 = enabled, 1 = disabled)
   < XX = checksum

Digital signal status (amplifier)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The console stores the signal status differently from the amplifier so it will
be confused by receiving the amplifier values while running (use the `Decode
state`_ message to fix this).

* ``00`` = N/A
* ``01`` = 5.1 signal detected (5.1 levels, no effects)
* ``0C`` = 2.0 signal detected (5.1 levels, effects mandatory)
* ``0E`` = unknown signal (decode/effect LEDs cycle continuously)

Digital signal status (console)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The console reports the signal status differently from the amplifier.

* ``00`` = N/A or unknown signal (decode/effect LEDs cycle continuously)
* ``01`` = no signal
* ``02`` = 5.1 signal detected (5.1 levels, no effects)
* ``03`` = 4.1 signal detected (4.1 levels, no effects)
* ``04`` = 3.1 signal detected (5.1 levels, no effects)
* ``05`` = 2.1 signal detected (2.1 levels, no effects)
* ``06`` = 2.0 signal detected (2.1 levels, no effects)
* ``07`` = 2.0 signal detected (5.1 levels, effects mandatory)
* ``08`` = signal detected (5.1 levels, no effects)

Write status/configuration
~~~~~~~~~~~~~~~~~~~~~~~~~~

Send the ``AA 0A`` message from the section above
(`Read status/configuration`_).

There's an amplifier bug in that standby status is never restored to 1, but it
can be set. Changing it from 1 to 0 will power on, changing it from 0 to 1 will
not go into standby. Try to avoid changing the power state with this command.

Reset idle time
~~~~~~~~~~~~~~~

Sent liberally by the console whenever user input is provided. Resets the idle
time maintained by the amplifier.

.. code-block:: none

   > 30
   < 30

Read idle time
~~~~~~~~~~~~~~

The idle time is not just reset by the console, it is also reset by the
amplifier itself when non-silent audio is being output. The console will send
this command every 60 seconds after the last user input.

If automatic standby is enabled and the time is reached the console will turn
the power off.

.. code-block:: none

   > 31
   < 31
   < AA
   < 0F = type
   < 03 = length of remaining data (excluding checksum)
   < 00 06 1C = idle time (U24BE in seconds)
   < XX = checksum

Read input volume
~~~~~~~~~~~~~~~~~

The console doesn't use this command, but you can find out the current volume of
the input. Silence is 0 and it looks like it goes up to 1,000,000 with some
maximum amplitude square waves. Normal values are around 1,000 to 2,000. Above a
certain volume the idle time will be reset and held at 0.

.. code-block:: none

   > 2F
   < 2F
   < AA
   < 08 = type
   < 03 = length of remaining data (excluding checksum)
   < 00 00 00 = volume (U24BE in unknown units)
   < XX = checksum

Read temperature
~~~~~~~~~~~~~~~~

The console doesn't use this command, but you can find out the current
temperature in the amplifier.

.. code-block:: none

   > 25
   < 25
   < AA
   < 0C = type
   < 05 = length of remaining data (excluding checksum)
   < 00
   < 00 = temperature 1 in Celsius
   < 00 = temperature 2 in Celsius
   < 00 = temperature 3 in Celsius
   < 00
   < XX = checksum

Power commands
--------------

Power on
~~~~~~~~

The first part of this is identical to `Headphones disconnected`_ so it should
be possible to power on with the `Headphones connected`_ sequence in its place.

The amplifier will power on with the currently configured input active, but the
effect is sent by the console automatically (`Effect selection`_).

.. code-block:: none

   > 11 11
   > XX (effect selection)
   > 39 38 30 39
   < 11 11
   < XX (effect selection)
   > 39 38 30 39

Power off
~~~~~~~~~

The ``36`` command here turns the speakers off and saves settings.

The ``37`` command's purpose is unknown.

Sends `Read status/configuration`_ at the end to update the console state.

.. code-block:: none

   > 30 37 36
   < 30 37 36
   > 34
   < AA 0A ...

Headphones connected
~~~~~~~~~~~~~~~~~~~~

.. code-block:: none

   > 10 10
   > 3F (effect selection)
   < 10 10
   < 3F (effect selection)

Headphones disconnected
~~~~~~~~~~~~~~~~~~~~~~~

.. code-block:: none

   > 11 11
   > XX (effect selection)
   < 11 11
   < XX (effect selection)

Volume/level commands
---------------------

The console implements the mute operation by setting the volume to 0 using lots
of `Main volume down`_ commands and then back up using lots of `Main volume up`_
commands. Going into standby while muted may result in a volume of 0 being
saved.

Main volume up
~~~~~~~~~~~~~~

Turning the volume up above level 43 is ignored and no command is sent.

.. code-block:: none

   > 08
   < 08

Main volume down
~~~~~~~~~~~~~~~~

Turning the volume down below level 0 is ignored and no command is sent.

.. code-block:: none

   > 09
   < 09

Mute
~~~~

Turn the volume down to level 0.

.. code-block:: none

   > 09
   > 09
   > 09 ...
   < 09
   < 09
   < 09 ...

The amplifier can also report a muted status (without changing the volume).
When the volume is next adjusted the console will unmute immediately:

.. code-block:: none

   < 20
   ...
   > 38
   > 08 or 09
   > 39

The console has its own independent "muted volume" and will use this to report
the mute status and when the button is pressed to unmute. At every power on this
"muted volume" is reset to 0.

Unmute
~~~~~~

Turn the volume back up.

.. code-block:: none

   > 38
   > 08
   > 08
   > 08 ...
   > 39
   < 38
   < 08
   < 08
   < 08 ...
   < 39

The amplifier can also report an unmuted status (without changing the volume).

.. code-block:: none

   < 21

If the console had muted then the volume level will still be 0.

Subwoofer level up
~~~~~~~~~~~~~~~~~~

Turning the subwoofer level up above 43 is ignored and no command is sent.

.. code-block:: none

   > 0A
   < 0A

Subwoofer level down
~~~~~~~~~~~~~~~~~~~~

Turning the subwoofer level down below 0 is ignored and no command is sent.

.. code-block:: none

   > 0B
   < 0B

Centre level up
~~~~~~~~~~~~~~~

Turning the centre level up above 43 is ignored and no command is sent.

.. code-block:: none

   > 0C
   < 0C

Centre level down
~~~~~~~~~~~~~~~~~

Turning the centre level down below 0 is ignored and no command is sent.

.. code-block:: none

   > 0D
   < 0D

Rear level up
~~~~~~~~~~~~~

Turning the rear level up above 43 is ignored and no command is sent.

.. code-block:: none

   > 0E
   < 0E

Rear level down
~~~~~~~~~~~~~~~

Turning the rear level down below 0 is ignored and no command is sent.

.. code-block:: none

   > 0F
   < 0F

Input selection
---------------

Mute the volume before changing inputs (`Volume/level commands`_) and switch to
the configured effect for the input (`Effect selection`_) before unmuting.

The "decode" light turns on if there is a digital signal from inputs 3, 4 or 5.

Input 1 (3.5mm TRS, 6 channels)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. code-block:: none

   > 09 ... (mute)
   > 02
   > XX (effect selection)
   > 08 ... (unmute)
   < 09 ... (mute)
   < 02
   < XX (effect selection)
   < 08 ... (unmute)
   < 39

Input 2 (RCA, 2 channels)
~~~~~~~~~~~~~~~~~~~~~~~~~

.. code-block:: none

   > 09 ... (mute)
   > 05
   > XX (effect selection)
   > 08 ... (unmute)
   < 09 ... (mute)
   < 05
   < XX (effect selection)
   < 08 ... (unmute)
   < 39

Input 3 (TOSLINK, S/PDIF optical fibre)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. code-block:: none

   > 09 ... (mute)
   > 03
   > XX (effect selection)
   > 08 ... (unmute)
   < 09 ... (mute)
   < 03
   < XX = `Decode state`_
   < XX (effect selection)
   < 08 ... (unmute)
   < 39

Input 4 (TOSLINK, S/PDIF optical fibre)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. code-block:: none

   > 09 ... (mute)
   > 04
   > XX (effect selection)
   > 08 ... (unmute)
   < 09 ... (mute)
   < 04
   < XX = `Decode state`_
   < XX (effect selection)
   < 08 ... (unmute)
   < 39

Input 5 (RCA, S/PDIF 75Ω coaxial)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. code-block:: none

   > 09 ... (mute)
   > 06
   > XX (effect selection)
   > 08 ... (unmute)
   < 09 ... (mute)
   < 06
   < XX = `Decode state`_
   < XX (effect selection)
   < 08 ... (unmute)
   < 39

Input 6 (3.5mm TRS on the console, 2 channels)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. code-block:: none

   > 09 ... (mute)
   > 07
   > XX (effect selection)
   > 08 ... (unmute)
   < 09 ... (mute)
   < 07
   < XX (effect selection)
   < 08 ... (unmute)
   < 39

Decode state
~~~~~~~~~~~~

* ``17`` = 5.1 signal detected (5.1 levels, no effects)
* ``18`` = no signal
* ``19`` = 4.1 signal detected (4.1 levels, no effects)
* ``1A`` = 3.1 signal detected (5.1 levels, no effects)
* ``1B`` = 2.1 signal detected (2.1 levels, no effects)
* ``1C`` = 2.0 signal detected (2.1 levels, no effects)
* ``1D`` = signal detected (5.1 levels, no effects)
* ``1E`` = 2.0 signal detected (5.1 levels, effects mandatory)
* ``1F`` = unknown signal (decode/effect LEDs cycle continuously)

The default state on the console is ``1F`` until this is provided by the
amplifier. The console will update the effect when the decode state changes (no
signal = effect disabled).

Effect selection
----------------

Using effects that are not compatible with the selected input has not been
tested.

3D effect
~~~~~~~~~

.. code-block:: none

   > 14
   < 14

4.1 effect
~~~~~~~~~~

.. code-block:: none

   > 15
   < 15

2.1 effect
~~~~~~~~~~

.. code-block:: none

   > 16
   < 16

Effect disabled
~~~~~~~~~~~~~~~

.. code-block:: none

   > 35
   < 35

No effect, headphones
~~~~~~~~~~~~~~~~~~~~~

.. code-block:: none

   > 3F
   < 3F

Speaker test
------------

While powered on hold down the "input" button for 5 seconds.

Tests speakers in this order:

* Front left
* Centre
* Front right
* Rear right
* Rear left
* Subwoofer

Start
~~~~~

Enter speaker test mode and `Select test speaker`_ "front left".

.. code-block:: none

   > 36
   > 22
   < 22
   > AA 07 ... (Select test speaker: front left)
   < 36

Select test speaker
~~~~~~~~~~~~~~~~~~~

.. code-block:: none

   > AA
   > 07 = type
   > 08 = length of remaining data (excluding checksum)
   > 01
   > 01 = speaker (01 front left, 10 centre, 02 front right,
                   08 rear right, 04 rear left, 20 sub, 00 none)
   > 00 00 00 00 09 2B
   > XX = checksum

Stop
~~~~

Exit speaker test mode, `Select test speaker`_ "none" and restore the previously
selected input (`Input selection`_).

.. code-block:: none

   > 33
   > AA 07 ... (Select test speaker: none)
   > 00
   < 33
   < 00

Configuration reset
-------------------

While in standby hold down the "input" button for 8 seconds.

Sends `Read status/configuration`_ at the end to update the console state.

.. code-block:: none

   > AA
   > 0E = type
   > 03 = length of remaining data (excluding checksum)
   > 20 = most significant byte of the idle time (lower bytes are reset to 0)
   > 00
   > 00
   > CF = checksum
   > AA
   > 0A = type
   > 14 = length of remaining data (excluding checksum)
   > 0A 15 15 15 00 00 00 00 00 00 03 00 00 00 06 01 03 00 00 00
   > 8C = checksum
   > 36
   < AA
   < FF = type
   < 01 = length of remaining data (excluding checksum)
   < 8A
   < 76 = checksum
   < 36
   > 34
   < AA 0A 14 0A 15 15 15 00 00 00 00 00 00 03 00 00 00 01 05 04 00 00 00 8C

Enable/disable automatic standby
--------------------------------

While powered on hold the "level" button for 5 seconds (until the level change
light goes out). The setting will be toggled. The console will also send the
current effect configuration in the wrong order so all of the effects set for
the inputs will be changed.

.. code-block:: none

   > AA
   > 0E = type
   > 03 = length of remaining data (excluding checksum)
   > 20 = set most significant byte of the idle time (lower bytes are reset to 0)
   > 00
   > 00
   > CF = checksum
   > AA
   > 0A = type
   > 14 = length of remaining data (excluding checksum)
   > 0A 15 15 15 00 00 00 00 00 00 03 00 00 00 01 05 04 00 00
   > XX = auto standby (0 = enabled, 1 = disabled)
   > XX = checksum
   > 36
   < AA
   < FF = type
   < 01 = length of remaining data (excluding checksum)
   < 8A
   < 76 = checksum
   < 36

The current idle time will become over 24 days which would normally result in an
automatic standby occurring but holding the button also repeatedly sends the
command to reset the idle time so it's unlikely to happen.


text:
#!/usr/bin/env python3

# Fairly straight port of
# https://github.com/pieroxy/lz-string/
# to Python.  Only decompress was ported

import re

def decompress(compressed):
    if (compressed is None) or (compressed == ''):
        return ''

    dictionary = {}
    enlargeIn = 4
    dictSize = 4
    numBits = 3
    (entry, result, w, c) = ('', '', '', '')
    (i, nnext, bits, resb, maxpower, power) = (0, 0, 0, 0, 0, 0)

    data_string = compressed
    data_val = ord(compressed[0])
    data_position = 32768
    data_index = 1

    for i in range(3):
        dictionary[i] = ''

    bits = 0
    maxpower = pow(2, 2)
    power = 1

    while power != maxpower:
        resb = data_val & data_position
        data_position >>= 1

        if data_position == 0:
            data_position = 32768
            data_val = ord(data_string[data_index])
            data_index += 1

        bits |= (1 if resb > 0 else 0) * power
        power <<= 1

    nnext = bits
    if nnext == 0:
        bits = 0
        maxpower = pow(2, 8)
        power = 1

        while power != maxpower:
            resb = data_val & data_position
            data_position >>= 1

            if data_position == 0:
                data_position = 32768
                data_val = ord(data_string[data_index])
                data_index += 1

            bits |= (1 if resb > 0 else 0) * power
            power <<= 1

        c = chr(bits)
    elif nnext == 1:
        bits = 0
        maxpower = pow(2, 16)
        power = 1

        while power != maxpower:
            resb = data_val & data_position
            data_position >>= 1

            if data_position == 0:
                data_position = 32768
                data_val = ord(data_string[data_index])
                data_index += 1

            bits |= (1 if resb > 0 else 0) * power
            power <<= 1

        c = chr(bits)
    elif nnext == 2:
        return ''

    dictionary[3] = c
    result = c
    w = result

    while True:
        if data_index > len(data_string):
            return ''

        bits = 0
        maxpower = pow(2, numBits)
        power = 1

        while power != maxpower:
            resb = data_val & data_position
            data_position >>= 1

            if data_position == 0:
                data_position = 32768
                data_val = ord(data_string[data_index])
                data_index += 1

            bits |= (1 if resb > 0 else 0) * power
            power <<= 1

        c = bits

        if c == 0:
            bits = 0
            maxpower = pow(2, 8)
            power = 1

            while power != maxpower:
                resb = data_val & data_position
                data_position >>= 1

                if data_position == 0:
                    data_position = 32768
                    data_val = ord(data_string[data_index])
                    data_index += 1

                bits |= (1 if resb > 0 else 0) * power
                power <<= 1

            dictionary[dictSize] = chr(bits)
            dictSize += 1
            c = dictSize - 1
            enlargeIn -= 1
        elif c == 1:
            bits = 0
            maxpower = pow(2, 16)
            power = 1

            while power != maxpower:
                resb = data_val & data_position
                data_position >>= 1

                if data_position == 0:
                    data_position = 32768
                    data_val = ord(data_string[data_index])
                    data_index += 1

                bits |= (1 if resb > 0 else 0) * power
                power <<= 1

            dictionary[dictSize] = chr(bits)
            dictSize += 1
            c = dictSize - 1
            enlargeIn -= 1
        elif c == 2:
            return result

        if enlargeIn == 0:
            enlargeIn = pow(2, numBits)
            numBits += 1

        if c in dictionary:
            entry = dictionary[c]
        else:
            if c == dictSize:
                entry = w + w[0]
            else:
                return None

        result += entry

        dictionary[dictSize] = w + entry[0]
        dictSize += 1
        enlargeIn -= 1

        w = entry

        if enlargeIn == 0:
            enlargeIn = pow(2, numBits)
            numBits += 1

def decode(value):
    value = re.sub("%u([0-9A-Fa-f]{4})", lambda m: chr(int(m.group(1), 16)), value)
    value = re.sub("%([0-9A-Fa-f]{2})", lambda m: chr(int(m.group(1), 16)), value)
    return value

if __name__ == "__main__":
    print("This module is not meant to be run directly")

repo_language: Python


text:
#!/usr/bin/env python3

from datetime import datetime, timedelta
import json
import nyt
import os
import sys
import textwrap
import time

def clean_date(val):
    if val == "now":
        # Make now actually tomorrow's date, to grab tomorrow's puzzle
        # if called near 10pm, and it's harmless to go too far in the future
        return (datetime.now() + timedelta(days=1)).strftime("%Y-%m-%d")
    else:
        return val

def main():
    if len(sys.argv) != 5:
        print(textwrap.dedent(f"""
            Usage:
                {os.path.split(__file__)[-1]} [browser] [start date] [end date] [dest folder]

            Will download all puzzles from start to end date, inclusive, skipping over
            any files that already exist.  Can use "now" for today's date, otherwise they
            must be formatted in yyyy-mm-dd
        """))
        exit(1)

    # Crack command line options
    browser = sys.argv[1]
    if browser not in nyt.get_browsers():
        print(f"ERROR: Unknown browser '{browser}', please select one of:")
        for key in nyt.get_browsers():
            print(f"  {key}")
        exit(1)
    start, end = clean_date(sys.argv[2]), clean_date(sys.argv[3])
    dest_folder = sys.argv[4]
    if not os.path.isdir(dest_folder):
        print(f"{dest_folder} does not exist!")

    # The endpoint that the NYTimes website uses for it's calendar
    api = "https://nyt-games-prd.appspot.com/svc/crosswords/v3/51312474/puzzles.json?publish_type=daily&sort_order=asc&sort_by=print_date&date_start=START&date_end=END"
    api = api.replace("START", start).replace("END", end)

    # Call into the helper here to load the endpoint
    cookies = nyt.load_cookies(browser)
    data = json.loads(nyt.get_url(cookies, api))

    # Run through each puzzle
    for cur in data["results"]:
        # Sometimes they publish just a PDF, ignore those
        if cur["format_type"] == "Normal":
            x = cur["print_date"]
            fn = os.path.join(dest_folder, x + ".puz")
            if not os.path.isfile(fn):
                # It's a new puzzle, grab it, conver it to a .puz file, and save it out
                data = nyt.get_puzzle_from_id(cookies, cur["puzzle_id"])
                puz = nyt.data_to_puz(data)
                puz.save(fn)
                print(f"Created '{fn}'")
                # Don't want to torture the website
                time.sleep(1.0)
            else:
                print(f"'{fn}' already exists.")

    print("All done.")

if __name__ == "__main__":
    main()


text:
#!/usr/bin/env python3

UPDATE_VERSION = True
PATCH_BROWSER_COOKIE3 = False

import subprocess
from zipfile import ZipFile
import os
import hashlib
import re
import version

def run(cmd):
    print(cmd)
    subprocess.check_call(cmd, shell=True)

if UPDATE_VERSION:
    with open("version.py", "r", encoding="utf-8") as f:
        data = f.read()
    data = re.sub(
        '(?P<pre>VERSION *= *"[0-9]+\\.)(?P<ver>[0-9]+)(?P<suf>")',
        lambda m: f"{m.group('pre')}{int(m.group('ver'))+1:02d}{m.group('suf')}",
        data,
    )
    with open("version.py", "w", newline="", encoding="utf-8") as f:
        f.write(data)

    run("git add version.py")
    run(f'git commit -m "Update version to {version.get_ver_from_source(data)}"')

if PATCH_BROWSER_COOKIE3:
    import browser_cookie3
    with open(os.path.join("patch", "patched_init.py"), "rt") as f:
        data = f.read()
    with open(browser_cookie3.__file__, "wt") as f:
        f.write(data)

run("python setup.py py2exe")

def get_dist_files():
    dirs = [("dist", "")]
    while len(dirs) > 0:
        dirname, pretty = dirs.pop(0)
        for cur in os.listdir(dirname):
            if cur != "nytxw_puz.zip":
                fn = os.path.join(dirname, cur)
                pn = cur if len(pretty) == 0 else pretty + "/" + cur
                if os.path.isfile(fn):
                    yield fn, pn
                elif os.path.isdir(fn):
                    dirs.append((fn, pn))

zip_name = os.path.join("dist", "nytxw_puz.zip")
with ZipFile(zip_name, 'w') as zipf:
    for fn, pn in get_dist_files():
        zipf.write(fn, pn)

print(f"Created {zip_name}")

with open(zip_name, "rb") as f:
    hashes = [
        (hashlib.md5(), "MD5"),
        (hashlib.sha256(), "SHA-256"),
        (hashlib.sha3_256(), "SHA-3"),
    ]
    while True:
        data = f.read(1048576)
        if len(data) == 0:
            break
        for hash, _ in hashes:
            hash.update(data)

    for hash, name in hashes:
        print(f"{name}: {hash.hexdigest()}")


text:
#!/usr/bin/env python3

# This next line must be exactly this format
VERSION = "1.12"
# The location of this file on GitHub
SELF_URL = "https://raw.githubusercontent.com/Q726kbXuN/nytxw_puz/master/version.py"

import re

# Pull out a version from a string version of this file
def get_ver_from_source(data):
    if hasattr(data, 'read'):
        data = data.read()
    if isinstance(data, bytes):
        data = data.decode("utf-8")

    m = re.search('VERSION *= *"(?P<ver>[0-9.]+)"', data)
    if m is None:
        return None

    return m.group("ver")

# Get the version of this file on GitHub
def get_ver_from_github():
    from urllib.request import urlopen
    try:
        resp = urlopen(SELF_URL, timeout=5).read()
        return get_ver_from_source(resp)
    except:
        return None

# Simple command line test of this
if __name__ == "__main__":
    print(f"Version embedded in file: '{VERSION}'")
    with open(__file__, "r") as f:
        print(f"Version found in file: '{get_ver_from_source(f)}'")
    print(get_ver_from_github())


text:
browser-cookie3
certifi
cffi
chardet
charset-normalizer
cryptography
fresh
future
idna
importlib-metadata
jeepney
keyring
pbkdf2
py2exe
pyaes
pycparser
pycryptodome
pyinstaller
requests
SecretStorage
urllib3
zipp