home.social

Search

239 results for “StacyKess”

  1. The Squeeze (1977)

    The Squeeze from 1977 is really a combination of the talent involved to keep things entertaining and thrilling. A forgotten British thriller that needs to be resurrected!

    garethmyles.com/the-squeeze-19

    #MovieStuffs #Reviews #1977 #BillJames #CarolWhite #DavidHemmings #EdwardFox #FreddieStarr #MichaelApted #Minder #StacyKeach #StephenBoyd #TheSqueeze #WhoseLittleGirlAreYou

  2. Back to #kotest rants. Because kotest has “built in coroutine support at every level” when an assertion fails, you can’t navigate to the matcher source code from the stack trace (Kotlin coroutines are stackless). So good luck if the error message is not very clear.

  3. I know I may be biased as it was MY choice for the podcast this week, but I am very much looking forward to discussing The New Centurions tonight. Jaw-dropping stuff.

    #film #cinema #movies #filmastodon #cinemastodon #mastomovies #TheNewCenturions #RichardFleischer #GeorgeCScott #StacyKeach #ErikEstrada #ScottWilson

  4. I know I may be biased as it was MY choice for the podcast this week, but I am very much looking forward to discussing The New Centurions tonight. Jaw-dropping stuff.

    #film #cinema #movies #filmastodon #cinemastodon #mastomovies #TheNewCenturions #RichardFleischer #GeorgeCScott #StacyKeach #ErikEstrada #ScottWilson

  5. I know I may be biased as it was MY choice for the podcast this week, but I am very much looking forward to discussing The New Centurions tonight. Jaw-dropping stuff.

    #film #cinema #movies #filmastodon #cinemastodon #mastomovies #TheNewCenturions #RichardFleischer #GeorgeCScott #StacyKeach #ErikEstrada #ScottWilson

  6. I know I may be biased as it was MY choice for the podcast this week, but I am very much looking forward to discussing The New Centurions tonight. Jaw-dropping stuff.

    #film #cinema #movies #filmastodon #cinemastodon #mastomovies #TheNewCenturions #RichardFleischer #GeorgeCScott #StacyKeach #ErikEstrada #ScottWilson

  7. , 1934, has some very innovative camera tricks but is painfully bad to watch through modern eyes.

    I like a lot of old movies but plenty of don't hold up at all outside of being origins of techniques and tropes.

    I watched a trailer for 's 1956 remake of his original, and that looks almost as outdated and painful to sit through, but it showed where the classic video got its knife in the back scene

  8. 🃏 STACKS OF GOONZALO: The Gates🃏
    Word has come to the goons that a crime syndicate has invited themselves to the ancient burial grounds of the sea stackes to literally build their cruminal empire. The ghosts of past heroes are pretty angry and are pestering the local population for solutions, as Goonzalo, a powerful necromancer, is untouchable to them.
    A dungeon for Nate Treme's Tunnel Goons!
    #Dungeon23 #TTRPG #OSR #TunnelGoons

  9. #TheManWhoKnewTooMuch, 1934, has some very innovative camera tricks but is painfully bad to watch through modern eyes.

    I like a lot of old movies but plenty of #classics don't hold up at all outside of being origins of #filmmaking techniques and tropes.

    I watched a trailer for #Hitchcock's 1956 remake of his original, and that looks almost as outdated and painful to sit through, but it showed where the classic #SaturdayNightLive #ColdAsIce #StacyKeach video got its knife in the back scene #SNL

  10. Sony a7R VI Has a Stacked 66.8MP Sensor and Captures 30 FPS Bursts

    Sony has unveiled the a7R VI, the company’s latest high-resolution full-frame mirrorless camera. However, this time it’s not…
    #NewsBeep #News #US #USA #UnitedStates #UnitedStatesOfAmerica #Technology #fullframe #Sony #sonya7rvi #sonyalpha #stackedsensor
    newsbeep.com/us/640917/

  11. Z80 and AY-3-8910 – Part 2

    I’ve spent a bit of time looking at the “Tester” part of the AY driver code for Tim Follin’s music archive that I talked about in Z80 and AY-3-8910.

    This is documenting what I think I’ve worked out so far for the tester code.

    The Sound Tester

    As previously mentioned, there are essentially three parts to the code in Follin archive:

    • The tune and effect data.
    • Ste Ruddy’s Sound Driver.
    • A tracker-style (ish) tester UI application.

    The first part looked at the sound driver itself, and essentially skipped over the tester part of the code. This post picks up on that tester code.

    Reminder, from part one, the main structure is as follows:

    Code_Start: EQU 40000
    Data_Start: EQU 50000

    ;-----------------------------
    ORG Code_Start

    ; The UI/tester code
    TESTER:
    LOOP: Calls the following for each scan:
    HALT - Suspends until an interrupt comes in?
    CALL UPDATE
    CALL REFRESH
    CALL CLOCK
    CALL KEYSCAN
    Repeat as necessary

    KEYSCAN: UI scanning
    CLOCK: Possibly maintain a 50Hz refresh rate clock?
    UPDATE: Loads the internal state of all sound variables from
    the driver and displays them in real time via the UI.

    ; The sound driver
    CODE_TOP:
    TUNE: Select which tune to play.
    TUNE_IN: Init all internal sound state variables for a new tune.
    TUNEOFF: Stop a playing tune, eg to change tune or start an FX.

    FX: Start playing an FX.
    FLOOP: Keep processing FX instructions until complete.

    REFRESH: "run" a scan of the sound driver updating and outputting the sound

    The Tester Code

    Initialisation information and main screen data:

    ;**************************************

    ; Z80 AY MUSIC DRIVER

    ;**************************************

    ; ORG 40000
    ; LOAD 0C000H

    ;======================================
    ;STACK DEPTHS

    SD: EQU 3

    ;======================================

    ASCII: EQU 23560 ; 23560 = $5C08 = System Variable "LAST K"

    TESTER: PUSH AF
    PUSH BC
    PUSH DE
    PUSH HL

    XOR A ; ASCII = MINS = SECS = 0
    LD (ASCII),A
    LD (MINS),A
    LD (SECS),A

    CALL TUNEOFF ; TUNE initialisation
    CALL STACKMESS ; Kick off the Tester code!

    DB CLS ; The start of the main UI data
    DB AT,0,0
    DB INK,01010111B
    DB "'AY' MUSIC DRIVE"
    DB "R V2 BY S.RUDDY"

    ... Skip ...

    DB INK,64+5
    DB "VOLUME "
    DB " "
    DB 255

    ... Skip ...

    AT: EQU 22
    INK: EQU 16
    CLS: EQU 15

    STACKMESS: POP IX
    CALL MESS
    JP (IX)

    There is a whole lot of screen data in DB blocks which includes some “op codes” that are defined later: AT, INK, CLS. These are special codes that are used by the ROM-based print routines (more here), as used by Sinclair BASIC, but in this case they are spelt out directly, later in code. The final 255 signifies the end of the screen data.

    So how are these definitions handled? That all comes up in the “MESS” routine I’ll get to in a moment, but first that “STACKMESS” routine needs a bit of explanation.

    When a CALL instruction happens, such as the CALL STACKMESS at the start, the current program counter gets pushed onto the stack. In this case the current PC will point to the instruction after the CALL, which happens to be the start of the screen data. So the POP IX will grab the address of the screen data and drop it into IX and then call the “MESS” function to actually get on with it!

    But before I get to that, there is some more code after the screen data:

                    LD HL,CALC1
    PUSH HL
    LD A,H
    LD DE,4067H ; Output high byte
    CALL HEX
    POP HL
    LD A,L
    LD DE,4069H ; Output low byte
    CALL HEX

    LD HL,(CALC2)
    PUSH HL
    LD A,H
    LD DE,4071H ; Output number of Tunes
    CALL HEX
    POP HL
    LD A,L
    LD DE,4073H ; Output number of effects
    CALL HEX

    LD HL,CALC1
    LD DE,(CALC2)
    ADD HL,DE
    PUSH HL
    LD A,H
    LD DE,407CH ; Not entirely sure what this is outputting...
    CALL HEX
    POP HL
    LD A,L
    LD DE,407EH
    CALL HEX

    This is writing some basic data out to the display. CALC1 seems to relate to code section size. I believe CALC2 is the start address of the tune data, which is the following:

                    ORG Data_Start

    TUNES: EQU 5
    EFFECTS: EQU 21

    All three of these sections are outputting a 16-bit value in two single-byte chunks using the “HEX” routine, which takes a screen address (in the range $4000-$57FF) and outputs a hex number at that screen location.

    So while I’m at it then, how is that HEX function working?

    ;--------------------------------------
    HEX: INC DE ; DE contains the screen address to use
    PUSH AF ; Start with DE+1
    CALL ONEnib ; Write out the LOW 4-bits
    POP AF
    RRA ; A = A>>4
    RRA ; to write out HIGH 4-bits
    RRA
    RRA
    DEC DE ; Back to original DE screen address
    ONEnib: AND 15 ; A = A & 0xF
    ADD A ; BC = A * 2
    LD C,A
    LD B,0
    LD HL,ROM_TAB ; Read from ROM_TAB[BC]
    ADD HL,BC
    LD A,(HL)
    INC HL
    LD H,(HL)
    LD L,A ; HL = (uint16_t)ROM_TAB[A]
    MIKESbug: LD C,D ; So HL now points to character bitmap in ROM
    LD B,8 ; Write out 8 bytes to display memory directly
    PRloop: LD A,(HL) ; (DE) = (HL)
    LD (DE),A
    INC HL ; HL++
    INC D ; NB: Layout of display mem means D++ is next line of char
    ; for same value of E.
    DJNZ PRloop ; WHILE (B-- > 0)
    LD D,C ; (Restore D before returning, so DE still = screen addr)
    RET

    ROM_TAB: DW 3D80H ; ROM character set: 3D80 = "0"
    DW 3D88H ; Each char = 8 x 8 bits
    DW 3D90H
    DW 3D98H
    DW 3DA0H
    DW 3DA8H
    DW 3DB0H
    DW 3DB8H
    DW 3DC0H
    DW 3DC8H ; = "9"
    DW 3E08H ; = "A"
    DW 3E10H
    DW 3E18H
    DW 3E20H
    DW 3E28H
    DW 3E30H ; = "F"

    This is making use of the character set stored in the Spectrum ROM (more here) which is indexed via a 16-word jump table mapping the characters onto each of the 16 hex characters: 0..9, A..F.

    Then each byte, 8 in total, of the character is written directly out to the Spectrum screen memory taking advantage of the odd formatting of the screen memory to easily skip to the next line of the display for each line of the character (more here).

    So before I get into the main update loop, how the screen initialised and set up? That happens in the “MESS” and some ancillary functions.

    MESS:           LD A,(IX+0)         ; At this point, McursorX, McursorY = (0,0)
    INC IX ; So read a byte of screen data
    OR A
    RET M ; Stop IF A=255 (i.e. negative)
    CP 32
    JR C,Mcontrol ; IF A<32 process control character then RET back to "MESS"
    CALL Mgetchar ; ELSE Process character
    CALL Mgetaddr ; Get screen address for next output in DE
    CALL MIKESbug ; Output the character
    CALL PRattr ; Set the colour attributes
    CALL INCcursor ; Update the screen position for the next byte of screen data
    JR MESS

    Mcontrol: LD HL,MESS ; Stick the address of "MESS" on the stack for the RET
    PUSH HL
    CP 15 ; IF A == CLS
    JR Z,Mcls
    CP 22 ; IF A == AT
    JP Z,Mat
    CP 16 ; IF A == INK
    JR Z,Mink
    RET ; RETurn to "MESS"

    Mcolour: DB 0 ; Working variables for cursor position and colour
    McursorX: DB 0
    McursorY: DB 0 ; Has to be directly after McursorX (see later)

    Mink: LD A,(IX+0) ; Process INK to set colour
    INC IX
    LD (Mcolour),A
    RET

    Mcls: LD HL,4000H ; Process CLS to clear screen
    LD (HL),L
    LD DE,4001H
    LD BC,1AFFH
    LDIR
    LD (McursorX),BC
    RET

    INCcursor: LD HL,McursorX ; Moves the cursor on one position
    LD A,(HL)
    INC A
    AND 31
    LD (HL),A ; X++; X = X % 32
    RET NZ ; IF X==0; Y++
    INC HL ; Assumes McursorY is McursorX++
    INC (HL)
    RET

    Mgetchar: LD L,A ; HL = A*8 + 3C00
    LD H,0 ; Note: A > 32; where 32="Space"
    ADD HL,HL ; In ROM, space is address 3D00
    ADD HL,HL ; 32 * 8 = 0x100
    ADD HL,HL
    LD BC,3C00H
    ADD HL,BC ; HL = Start address of character map for char in A in ROM
    RET

    .... skip ....

    Mgetaddr: LD A,(McursorY) ; Calculate the screen address for (McursorX, McursorY)
    AND 18H
    OR 40H
    LD D,A
    LD A,(McursorY)
    RRCA
    RRCA
    RRCA
    AND 0E0H
    LD E,A
    LD A,(McursorX)
    ADD E
    LD E,A
    RET ; DE = required screen address

    Mat: LD A,(IX+0) ; Set cursor to provided X, Y in screen data
    LD (McursorX),A
    INC IX
    LD A,(IX+0)
    LD (McursorY),A
    INC IX
    RET

    PRattr: LD A,D ; Get address of ATTRibute memory
    RRA
    RRA
    RRA
    AND 3
    OR 58H
    LD D,A
    LD A,(Mcolour)
    LD (DE),A ; And set the colour
    RET

    Basically this loop keeps working on the provided screen data until the value 255 is found, at which point it returns. There are two paths for handling the data:

    • IF the value is < 32 then it is a control value. Only CLS, AT and INK are recognised.
    • ELSE the value is assumed to be an ASCII character and is displayed.

    Whatever is happening, happens at the coordinates given by (McursorX, McursorY) which start out as (0,0) and get updated automatically when a character is output, or in response to an AT command. INK will set the required colour in Mcolour, which again starts out as 0. This is applied after the character is written to the screen, using the PRattr function.

    There is a fun bit of optimisation going on in Mcontrol. At the start it pushes the address of the MESS function on the stack, which means that the RET will jump back to the start of MESS rather than where the jump happened to Mcontrol itself.

    There is another shortcut in the Mcls function: LDIR. From http://z80-heaven.wikidot.com/instructions-set:ldir: “Repeats LDI (LD (DE),(HL), then increments DE, HL, and decrements BC) until BC=0.” By setting the contents of HL (the first byte of the display) to zero, this will tile that same value across the display memory until BC, which starts at $1AFF, is zero. This will zero the whole display – both pixels and attributes – from 0x4000 through to 0x5AFF.

    Now finally, we get to the main update loop.

    LOOP:           
    HALT
    CALL UPDATE ; Update the display from the current Sound parameters
    LD A,2
    OUT (254),A ; Set border to 2
    CALL REFRESH ; Update the sound driver parameters
    XOR A
    OUT (254),A ; Set border to 0
    CALL CLOCK ; Run 50Hz clock
    CALL KEYSCAN ; Guess what - scans the keyboard 🙂
    LD A,07FH
    IN A,(254) ; Reads 0x7FFE which is the bottom row of the keyboard
    AND 1
    JP NZ,LOOP ; Checks bit 0, which is the SPACE key
    LD BC,65533 ; AY OUTPUT PORTS (FFFD, BFFD)
    LD A,7
    OUT (C),A
    LD BC,49149
    LD A,63 ; Set AY register 7 to 63 - i.e. all channels OFF
    OUT (C),A

    POP HL
    POP DE
    POP BC
    POP AF
    RET

    I’m not going through the sub routines of the loop, other than to note the following:

    • UPDATE is a whole series of instructions that basically do the following to output the HEX value of a sound parameter:
    LD A, (contents of one of the sound variables)
    LD DE, (corresponding screen address for the variable to be displayed)
    CALL HEX
    • REFRESH runs the sound driver itself, as described in Z80 and AY-3-8910.
    • CLOCK decrements the FIFTY variable and every time it gets to zero updates SECS and MINS and writes them out to the display. As it also uses the HEX routine, I guess it is storing the time using binary-coded decimal (BCD).
    • KEYSCAN reads the last key pressed from the system variable location stored in ASCII (23560 / 0x5C08).

    At some point I might come back and work out what keys do what…

    Closing Thoughts

    I’d really like to get some of this code running on some of the alternate Z80 platforms I have. Getting the sound output shouldn’t be too much of an issue, but I’d really like to have some kind of display too.

    But as can be seen above, the tester UI is pretty well tied into the oddities of the ZX Spectrum display, so porting it won’t be trivial.

    I suspect there are already some existing AY/chiptune players that perhaps would be a better starting point, but from what I’ve seen they tend to stream the register data after having sampled it at regular intervals, which isn’t quite what I was after… there would be something really quite interesting about actually running Ste Ruddy’s Sound Driver with a Tim Follin soundtrack programmed in.

    Kevin

    #ay38910 #TimFollin #zxSpectrum
  12. Mini-Compendium: Power, Safety, Authority Gradients, and the Power of Elites

    Here’s some articles, mostly full-text links, exploring power within organisations.

    Includes broader social power, power gradients, voice, and more.

    Feel free to shout me a coffee if you’d like to support the growth of my site:

    https://buymeacoffee.com/benhutchinson

    Full-Text Articles

    [Below link will say ‘Discursive effects of safety science’. Download it and its a whole book with the above chapter]

    https://www.researchgate.net/profile/Johan-Bergstroem/publication/335162893_The_Discursive_Effects_of_Safety_Science/links/650ad3d6d5293c106cca099b/The-Discursive-Effects-of-Safety-Science.pdf#page=124

    https://sidneydekker.com/wp-content/uploads/2024/12/SafetyInPower.pdf

    https://sidneydekker.com/wp-content/uploads/2024/12/JustCultureCritique.pdf

    https://d1wqtxts1xzle7.cloudfront.net/79944444/1d996e_7f6d510450714d16a785e27021ff18b8-libre.pdf?1643583068=&response-content-disposition=inline%3B+filename%3DLeader_Humility_and_Team_Creativity_The.pdf&Expires=1742163884&Signature=dpjnEIAR6EST6HE0kx1~oMIMWZT7p~7tI4qslcYJO9tzlH5l8JsrCpijy4umQXbVzcBvJB799-d~rhpyacjjc0xF-SL0elgOB3llLFvyoWfjBzmEyjKVv8-nmFZNgByEjk9ymu5mzK5W5a9puCm5YBcOolRSmHzoHIlDDNEBxCr-sVGZddRRRxYtYKl83Qau5zlPOJq9nWSe7EIUZcB9-YD6i8jtSwXF5DiStJgRZRvR7ydIWxhKoZwCUe4qUPBAPYZvv3ybYIuARgj7KlEJV8mAPUw3MZSpROLY8YP~m52Yw6lJ8iCZMx2up2xyEi-gyoa2geJjmDaTB6Ic~BbX2g__&Key-Pair-Id=APKAJLOHF5GGSLRBV4ZA

    https://doi.org/10.1016/j.ssci.2024.106446

    https://pmc.ncbi.nlm.nih.gov/articles/PMC4880472/pdf/nihms5702.pdf

    https://www.researchgate.net/profile/Wai-Yoong/publication/362609810_Understanding_authority_gradient_tips_for_speaking_up_for_patient_safety_and_how_to_enhance_the_listening_response/links/67a268e296e7fb48b9b46fa6/Understanding-authority-gradient-tips-for-speaking-up-for-patient-safety-and-how-to-enhance-the-listening-response.pdf

    https://www.researchgate.net/profile/Erin-Stevens-2/publication/350469124_The_impact_of_power_on_health_care_team_performance_and_patient_safety_A_review_of_the_literature/links/608758b98ea909241e28c310/The-impact-of-power-on-health-care-team-performance-and-patient-safety-A-review-of-the-literature.pdf

    https://onlinelibrary.wiley.com/doi/pdf/10.1197/j.aem.2004.07.005

    https://eprints.lse.ac.uk/90953/1/Tear_Safety-culture-and-power.pdf

    https://ecampus.nmit.ac.nz/moodle/pluginfile.php/2178236/mod_resource/content/1/Trust%2C%20Power%20and%20safety%20in%20the%20social%20work%20supervisory%20relationship%20%282017%29.pdf

    https://research-repository.griffith.edu.au/server/api/core/bitstreams/6be4c986-c4d5-5145-9360-6ceb388de953/content

    https://sidneydekker.stackedsite.com/wp-content/uploads/sites/899/2017/09/ZeroVision.pdf

    https://www.academia.edu/download/86424812/j.ssci.2019.09.02820220524-1-1nt6327.pdf

    https://doi.org/10.1016/j.ssci.2018.10.025

    https://journals.sagepub.com/doi/pdf/10.1177/2327857921101130

    https://journals.sagepub.com/doi/pdf/10.1177/25160435211027035?fbclid=IwAR21-3M4frgjnjiiesS5EZCfvfnISjdz7M7P8E130r2NLIPcUrqflEellLk&

    https://doi.org/10.1016/j.ssci.2019.04.039

    https://www.tandfonline.com/doi/pdf/10.1080/09585192.2024.2342294

    https://digitalcommons.osgoode.yorku.ca/cgi/viewcontent.cgi?article=1001&context=ohlj

    https://eprints.lse.ac.uk/109877/1/Noort_et_al._MANUSCRIPT_for_LSE_online.pdf

    https://doi.org/10.1016/j.ssci.2020.105120

    https://www.ida.liu.se/~769A22/Seminarier/articles/safety_counterculture.pdf

    https://doi.org/10.3389/fpsyg.2019.00668

    https://research.vu.nl/ws/portalfiles/portal/2277897/202659.pdf

    https://journals.sagepub.com/doi/pdf/10.1177/0096340211426395

    https://www.researchgate.net/profile/Andrew-Hopkins-4/publication/279759571_The_Limits_of_Normal_Accident_Theory/links/590ef803a6fdccad7b123cb3/The-Limits-of-Normal-Accident-Theory.pdf

    https://www.academia.edu/download/107807207/soc4.1273720231125-1-c3885x.pdf

    https://www.tandfonline.com/doi/pdf/10.1080/1463922X.2021.1881653

    https://www.researchgate.net/profile/Susan-Silbey/publication/228173756_Taming_Prometheus_Talk_About_Safety_and_Culture/links/55103d080cf203521969d837/Taming-Prometheus-Talk-About-Safety-and-Culture.pdf

    https://safety177496371.wordpress.com/2022/02/08/ruthless-exploiters-or-ethical-guardians-of-the-workforce-powerful-ceos-and-their-impact-on-workplace-safety-and-health/

    https://safety177496371.wordpress.com/2025/01/23/safety-culture-and-power-dynamics-in-organizations/

    https://www.researchgate.net/profile/Erin-Stevens-2/publication/350469124_The_impact_of_power_on_health_care_team_performance_and_patient_safety_A_review_of_the_literature/links/608758b98ea909241e28c310/The-impact-of-power-on-health-care-team-performance-and-patient-safety-A-review-of-the-literature.pdf

    https://www.academia.edu/download/110471105/JHQ.000000000000025720240115-1-n29aqn.pdf

    https://www.scielo.br/j/rbso/a/ghnrhMFyqSssFxFFSMfQbXd/?format=pdf&lang=en

    https://dialnet.unirioja.es/descarga/articulo/9554587.pdf

    https://ap-st01.ext.exlibrisgroup.com/61SCU_INST/upload/1741316102864/The%20construction%20and%20legitimation%20of%20workplace%20bullying%20in%20the%20pu.pdf?Expires=1741316223&Signature=itZRT0uJOuRdUpI5C3P6RhfqsmZwlNkxQpZQVbs-OlGf4~VM9H7Hsog9a5Nd3X9WWTDqhARrGVNkArCuMcFeuEg38qP5zQdJzx~V7ldivDFG1IBjRzhKkDD1qPB5-0TSTODiNLdesbPVP6ya-inEspaJZVJuekE6WH5lf-TnDICzt5NS-eMYWxjZBtul1KYSdSNXh55As8qvaHpcDQVZzmUTGO9FJgFjtAJiKL~pyn7E~z5Cj13j-of5IfY~jLA6KNFZ-wrB9YBMLEHzqcsAIudz8QUICkkQYYvG4H8MFEESfS~ShEhvYowHBLg6fS0NzNTOzZBmQ4Ii3JWeoys5OQ__&Key-Pair-Id=APKAJ72OZCZ36VGVASIA

    https://www.academia.edu/download/49166705/j.socscimed.2009.09.05220160927-27290-19a6oxp.pdf

    https://www.academia.edu/download/30990385/2010_Clinical_supervision_Hdez_McDowell.pdf

    https://studystock.wordpress.com/wp-content/uploads/2013/11/understanding-power-in-organizations.pdf

    https://openaccess.city.ac.uk/id/eprint/8236/4/Annals%20accepted.pdf

    https://www.academia.edu/download/89536105/0003-066x.45.2.17920220812-1-11im1f6.pdf

    http://www.contrib.andrew.cmu.edu/~krack/documents/pubs/1990/1990%20Assessing%20the%20Political%20Landscape.pdf

    https://www.academia.edu/download/31144526/administrative_science_quarterly_7_1972_mechanic.pdf

    https://journals.sagepub.com/doi/pdf/10.1177/26317877221084714

    https://ascelibrary.org/doi/pdf/10.1061/%28ASCE%29LM.1943-5630.0000018?download=true

    https://www.researchgate.net/profile/Sean-Buchanan/publication/327477734_Power_Institutions_and_Organizations/links/64888219d702370600ef726d/Power-Institutions-and-Organizations.pdf

    https://www.researchgate.net/profile/Belle-Ragins/publication/232499085_Gender_and_Power_in_Organizations_A_Longitudinal_Perspective/links/56baaf1f08ae3af6847d8c13/Gender-and-Power-in-Organizations-A-Longitudinal-Perspective.pdf

    https://www.researchgate.net/profile/Stewart-Ranson/publication/247733580_Power_and_Advantage_in_Organizations/links/0deec53c68032b4ade000000/Power-and-Advantage-in-Organizations.pdf

    https://citeseerx.ist.psu.edu/document?repid=rep1&type=pdf&doi=c72a7081f0f19c3f3b4e99c492f16ac2f8a21c92

    https://citeseerx.ist.psu.edu/document?repid=rep1&type=pdf&doi=902977fcabe0928dc829ca14ef62a8b26e5b8dad

    https://www.jaapboonstra.nl/wp-content/uploads/2013/01/Power-dynamics-and-organizational-change2.pdf

    https://www.researchgate.net/profile/Jori-Kalkman/publication/308898552_Inter-Organizational_Disaster_Management_Projects_Finding_the_Middle_Way_between_Trust_and_Control/links/5c5a953692851c48a9bd7ccc/Inter-Organizational-Disaster-Management-Projects-Finding-the-Middle-Way-between-Trust-and-Control.pdf

    https://www.humanfactors.lth.se/fileadmin/lusa/Sidney_Dekker/articles/2003_and_before/SuparamaniamDekker2003.pdf

    https://mutualaiddisasterrelief.org/wp-content/uploads/2024/05/The_Biopolitics_of_Disaster_Power_Discourses_and_Practices.pdf

    https://www.diva-portal.org/smash/get/diva2:513208/FULLTEXT01.pdf

    https://onlinelibrary.wiley.com/doi/pdf/10.1002/rhc3.12218

    https://www.researchgate.net/profile/Howard-Schwartz-2/publication/40955166_On_the_psychodynamics_of_organizational_disaster_The_case_of_the_space_shuttle_Challenger/links/5cd08c0a92851c4eab87d179/On-the-psychodynamics-of-organizational-disaster-The-case-of-the-space-shuttle-Challenger.pdf

    https://doi.org/10.1016/j.ssci.2024.106446

    https://link.springer.com/content/pdf/10.1007/s10111-019-00545-8.pdf

    https://www.researchgate.net/profile/Emil-Kotsev/publication/381496413_Managing_the_Distance_with_the_Superior_Toward_a_Resolution_of_a_Subordinate_Manager’s_Dilemma/links/667a797b1dec0c3c6fa322e1/Managing-the-Distance-with-the-Superior-Toward-a-Resolution-of-a-Subordinate-Managers-Dilemma.pdf

    https://www.academia.edu/105928772/Danger_zone_Men_masculinity_and_occupational_health_and_safety_in_high_risk_occupations

    https://scholarlypublications.universiteitleiden.nl/access/item%3A3250217/view

    https://www.ida.liu.se/~769A22/Seminarier/articles/safety_counterculture.pdf

    https://doi.org/10.1016/j.ssci.2020.105120

    https://www.academia.edu/91832217/Power_organization_design_and_managerial_behaviour

    https://journal.psych.ac.cn/acps/EN/Y2022/V54/I5/549

    Abstracts & Extracts

    https://doi.org/10.1016/j.ssci.2008.02.004

    https://asmepublications.onlinelibrary.wiley.com/doi/abs/10.1111/medu.12947

    https://doi.org/10.1016/j.ssci.2013.10.013

    https://doi.org/10.1111/1468-5973.00032

    https://press.princeton.edu/books/paperback/9780691004129/normal-accidents?srsltid=AfmBOorMEgPZMJ-EM2pIOy_Mz1WhKd8IC6z_NGRBcycAgOP7Ktza7r5v

    https://press.uchicago.edu/ucp/books/book/chicago/M/bo3645893.html]

    LinkedIn post: https://www.linkedin.com/pulse/mini-compendium-power-safety-authority-gradients-ben-hutchinson-vttnc

    #accident #authorityGradient #downwardVoice #elites #politics #power #powerGradient #psychologicalSafety #safety #safetyScience #speakingUpToPower #voice

  13. Error 502 ja sivustojen backup-näyttö

    eksis.one/palvelimet/error-502

    Tuskin kukaan pitää tilanteesta, jossa selain esittää kliinisen kylmän error 500/502/503/504 virheen. Kävijät siksi, että eivät näe sisältöä. Ylläpito siksi, että 50x-sarjan virheet kertovat, että jokin serverillä on nurin, mutta ei anna pienintäkään viitettä syystä.

    Kertomattomuus johtuu siitä, että viallinen ei pysty kertomaan mihin sattuu, ja kuunteleva ei ymmärrä mistä on kyse.

    Omassa stackissa Nginx – Varnish – Apache2 (PHP, MariaDB, WordPress) virhekoodi saattaa antaa jotain suuntaa.

    • 500: Nginx tai virtuaalihostin konffi on rikki
    • 502: Varnish on kaatunut
    • 503: useimmiten Apache2 on kaatunut
    • 504: Apachen takana oleva WordPress on sekaisin

    Mutta tuohonkin on olemassa poikkeuksia ja kaikki riippuu siitä miten ongelmakohta pystyy vastaamaan pyyntöihin ja miten kyselijä ilmoituksen tulkitsee.

    Varajärjestelmän varajärjestelmä

    Olen kehittänyt 50x-sarjan virheistä itselleni eräänlaisen pakkomielteen. Osaksi koska inhoan niitä syvästi ja osaksi siksi, että pääsääntöisesti minä olen syypäänä onnistunut kaatamaan tai rikkomaan jotain. Aika harvoin ohjelmat itsessään hajoavat, vaikka niitäkin tapauksia on ollut.

    Katkokset ovat siten suolaa haavoihin hierova muistutus kädettömän sysadminin ammattitaidottomuudesta. Tai en tiedä voidaanko tällaisen kotitarveylläpitäjän kohdalla puhua ammattitaidottomuudesta. Kyse on pelkästään kyvyttömyydestä. Ja huolimattomuudestakin aika usein.

    Ongelman toinen puoli on se, että en aina tiedä suoraan miten virheen korjaan. Tunteja voi kulua, ja koko sen ajan jokainen sivusto on saavuttamattomissa. Joten tarvitsin mahdollisuuksien mukaan joko informatiivisemmat virhesivut tai jonkun backup-järjestelmän, joka esittää sisällön.

    Palapeli palapelin selässä

    Minulla työnkuva on useimmiten mallia on ongelma, etsin ensimmäisen ratkaisun, ongelma laajenee, etsin uuden ratkaisun, en tiedä mihin päädyn ja miten.

    50x-virheiden kohdalla tuo tarkoittaa sitä, että ensin lähdin säätämään virhesivuja. Niiden muuttaminen on aika triviaalia, mutta lisäinformaation saaminen ei ollut. Joten tyydyin vain muuttamaan tekstiä ja kerjäämään ihmisiä kertomaan, että sivustot ovat alhaalla.

    En yleensä saanut mitään tietoa kaatumisista, koska kaupalliset monitorit ovat kalliita ja ilmaiset ratkaisut aina jollain tapaa ongelmallisia.

    Joten seuraavaksi aloin selvittämään miten pystyisin saamaan tiedon minulle sopivalla tavalla, kun jokin palvelu ei tee sitä mitä sen kuuluisi. Olin aiemmin oivaltanut, että sellaista outoutta kuin API voidaan käyttää keskustelujen avaamiseen Discourse-foorumillani — ja se osaa lähettää push-ilmoituksia minulle.

    Joten ensin pienen ja sitä seuranneen isomman riidan jälkeen sain rakennettua tavan, jossa Nginx kertoo Plesk-serverille 50x-virheestä. Se taasen esittää kustomoidun virheilmoituksen ja avaa Discoursessa ketjun sille virheelle.

    Varnish tuuraa Apachea

    Siinä samalla oli alkanut itää ajatus esittää backup-sisältöä. Miksi tyytyä virheilmoituksiin, jos voisikin esittää edes jotain sisältöä.

    Helpointa, ainakin sillä hetkellä, oli keskittyä 503/504-virheisiin. Tilanteisiin, joissa Varnish käy ja kukkuu, mutta Apache2 tai WordPress on kaatunut. Helpointa siksi, että minullahan oli jo sisältö valmiina, ainakin osaksi: Varnishin cachessa. Se sisältö ei muutoinkaan koskaan piittaa backendistä; se on cachen pointti ja merkitys. Cache hyödyttää korvikesisältönä vain, jos cache lämmitetään, eli kaikki kopioidaan sinne. Se tavataan tehdä wgetillä — joka kykenee luomaan kohtuullisesti toimivan staattisen version sivustoista.

    Joten kun alkuperäinen tavoite oli vain lämmittää cache, niin olin tullut luoneeksi siinä ohessa snapshot-sisältöä. Tein siitä varajärjestelmän varajärjestelmän.

    Apache2/WordPress kaatuu. Niin kauan kun kukaan ei tee POST-kutsua tai pyydä sellaista, jota ei voida cachettaa, niin kukaan ei tiedä ongelmista mitään. Kaikki tulee 1:1 kopioina Varnishista.

    Varnish saa tiedon backendin hengettömyydestä, kun pyydetään sisältöä, jota ei löydy cachesta. Se vaihtaa backendiä ja hakeekin Nginxin kautta snapshot-sisällön, jos se on kelvollista (GET/HEAD) , tai esittää tympeän virheilmon (POST, admin jne.). Kyllä, olisin voinut tuottaa Nginxin kautta dynaamisen sisällön, mutta en lähtenyt sille tielle. En halua sählätä liikaa tietokannan kanssa. Jos se hajoaa, vaikka kaksoiskäytön takia, niin olen liian syvissä vesissä täysin uimataidottomana. Pelkään tietokantoja.

    Kun snapshot-sisältöön siirrytään, niin siitä menee tieto Pleskille, joka kertoo Discourselle, joka kertoo minulle.

    Samaan aikaan kävijät eivät tiedä mitään ongelmista, cachen takia, tai saavat ehkä hieman rikkinäisen, mutta käytettävän sisällön. Eivät jotain error-ilmoitusta.

    Kuka tuuraa Varnishia?

    Minulla useimmiten kaatuu Varnish. Ei sen takia, että se olisi epävakaa, vaan koska säädän sitä aina kun on liikaa vapaa-aikaa. Minun säätöni tapaavat olla aika riskialttiita. Joten tarvitsin jonkin turvajärjestelmän Varnishin kaatumisen varalta.

    Minulla on Nginx ja minulla on valmis snapshot-sisältö. En siis tarvinnut muuta kuin tavan tunnistaa 502-virhe, eli Varnishin kaatuminen, ja sen myötä kääntääkin proxy-liikenne uuteen suuntaan: snapshot-serverille, joka oli Nginxin hoivissa.

    Tässäkin vain staattiset kyselyt kelpasivat, koska tavoitteeni ei ollut milloinkaan rakentaa täysin toimivaa korvaajaa. Halusin tarjota jotain sisältöä virheilmoituksen sijaan.

    Sain sen rakennettua. Mutta minulla oli melkoisia ongelmia saada kävijät pois emergency-reitiltä takaisin normaaliin siinä vaiheessa, kun Varnish palasi linjoille.

    Tiesin entisestään, että mm. Bing ei piittaa 410 virheistä, tai redirect 301/302 erosta, vaan koputtelee maailman tappiin saakka kaikkea löytämäänsä. Päinvastoin kuin mitä Google selittää, niin samaa tekee osaltaan googlebot ja varsinkin google-image. Mutta minulle oli yllätys kuinka vähän laillisetkin botit piittasivat 302 käännön väliaikaisuudesta sekä cache-headereista, jotka ohjasivat olemaan tallentamatta sisältöä.

    Ne indeksoivatki suunnilleen kaiken ja väliaikaisiksi leimattuja emergency-polkuja alkoi löytymään hakutuloksista. Tuo ei ollut haluttua.

    Snapshot versio 2

    Nginxin serveriblokit alkoivat lisäksi olla melkoista sekasotkua. Oli mappia ja oli if-lausetta. Kaikki hyvin pitkälle siksi, että kun kävijän saaminen emergency-reitille ja snapshot-serverille ei ollut kovinkaan vaikeaa, niin en saanut selaimia pois hätäreitiltä, kun paniikki oli ohi.

    Javascriptillä toki olisi onnistunut, mutta siitä en tiedä mitään. En minä ole koodari. Minä olen kopypeistaaja.

    Riitelin taas kerran Nginxin kanssa tämän asian puitteissa. Olin sammuttanut Varnishin simuloidakseni Varnishin kaatumista ja koska normaalisti Varnish käynnistyy hitaasti, niin hyödynsin sen panic-toimintaa simulaationa tilanteen normalisoitumisessa. Se kun käynnistyy silmänräpäyksessä.

    Minulla on panic-scripti tilanteita varten, jossa Varnish kaatuu, ja tiedän korjauksen vievän aikaa. Siinä master ohitetaan CLI:n avulla. Joten jos Varnishin ytimessä henki pihisee, niin saan sen käyntiin. Toki menetän cachen ja sellaisia asioita, mutta sivustoille pääsee Varnishin ollessa vain tyhmä putki.

    Jäin testeissäni ihmettelemään mitä olin juuri tehnyt. Olin käynnistänyt tmuxin, koska CLI täytyy olla koko ajan käynnissä, ja potkaissut Varnishin prosessin käyntiin. Mutta virallisestihan Varnish oli edelleen naamallaan, ja sehän on juurikin se tilanne, jonka hätätoimintoa yritin Nginxillä rakentaa.

    Olen tehnyt tuon ennenkin, monta kertaa. Kuten kun sekoilin kääntämisessä, ja rikoin Varnishin, niin pyöritin sitä tmuxin sisällä CLI:n kautta lähes viikon. Joten… miksi en tekisi samaa nyt, mutta ilman tmuxia ja automatisoituna, jolloin minun ei tarvitse riidellä niin paljon emergency-polun kanssa.

    Puolikkaan työpäivän ja useiden kokeilujen ja erehdysten jälkeen minulla on nyt järjestelmä, jossa Varnishin kaatuessa 10 sekunnin ajan esitetään virheilmoitus ja pyydetään kävijältä reload (tuo viive on Pleskin takia, luultavasti 5 sekuntiakin riittäisi varnistamaan, että API-pyyntö lähtee Discourseen).

    Seuraavaksi käynnistetään Varnish CLI-malliin mutta automaattisesti scriptillä. Taustalla käydään kyselemässä aika ajoin onko aito Varnish vihdoin järjissään ja kun se on käynnistynyt, niin vaihdetaan paniikki-Varnishista aitoon normaaliin Varnishiin.

    Eikä kukaan huomaa mitään — paitsi sen ensimmäisen 10 sekunnin ajan.

    Mutta… jos Varnish kaatuu oikeasti?

    Tuo järjestelmä ei ole todellakaan aukoton. Kaikkea muuta. Mutta noin 98 kertaa sadasta Varnishin kaatuminen on sellainen, että uusi instanssi saadaan käynnistettyä.

    Jos Varnish on täysin kuollut, niin sille ei ole varsinaista varajärjestelmää. Snapshot-serverin emergency ei onnistu minun taidoillani. Se hemmetin emergency-polku pysyy siellä, kiitos selainten. Ja koska moinen päätyy hakukoneisiin, niin en käytä sitä. Esitän mieluummin virheilmoitusta.

    Lisään emergencyn polkuun kahdesta syystä. Ensimmäinen on, että sillä estän wgetin muokkaaman (ja hieman rikkoman) sisällön saastuttamasta aitoa cachea. Toinen syy on, että silloin urista näkee, että ei olla normaalitilanteessa.

    Jos backend on saavuttamattomissa, niin Varnish ja Nginx käyttävät cacheamattoman sisällön kohdalla emergency-polkua. Mutta cachen lämmitys on noin 95 prosenttisen tehokas, joten se tulee käyttöön erittäin harvoin. Kun tulee, niin Varnish siivoaa emergemcy-osan pois vastauksesta tilanteen normalisoiduttua.

    Ihmiset näkevät emergencyn urlissa korjaantumisen jälkeenkin, paitsi jos klikkaavat jotain uutta linkkiä — merkintä lisätään Nginxissä, ei snapshotteihin — mutta botit näkevät polun oikein oikeilla headereilla. Eikä ihmisistä ole väliä, koska selaimethan eivät enää edes varsinaisesti näytä urlia.

    Mutta jos Varnish on totaalisen kuollut, niin laitan Nginxin juttelemaan suoraan Apachen kanssa. Se on vielä manuaalinen säätö, mutta tiedän miten sen saisi semiautomaattiseksi — ehkä teen sen muutoksen, kun taas on hieman liikaa vapaa-aikaa.

    Varajärjestelmä tämä kirjoitettaessa

    Jos backend kaatuu, niin Varnish käyttää cachea tai ohjaa Nginxin kautta snapshot-sisältöön.

    Jos Varnish kaatuu, niin käynnistetään toisenlainen Varnish, joka keskustelee suoraan backendin kanssa.

    Jos Varnish kaatuu totaalisesti, niin pakotan manuaalisesti Nginxin juttelemaan Apachen kanssa.

    Jos Nginx kaatuu… tuota en ole vielä tehnyt, mutta minulla on alustava konsepti. Ehkä saisin Hitchin tai muun SSL/TSL-terminaattorin hoitamaan saapuvan liikenteen ja kääntäisin sen tyhmälle paniikki-Varnishille.

    Miten koostin nykyisen Varnish korvaa Varnishin?

    Alleviivaan jo mainittua: en ole koodari. Tämän olisi varmaan voinut tehdä helpomminkin, mutta minä en tätä kummallisempaan kyennyt.

    Nginx kääntää uudelle proxylle:

    Ennen server-blokkia (käytä omia porttejasi):

    ❯ Näytä koodi
    [map $panic $varnish_upstream ](#)    0 127.0.0.1:8080;  # normaali Varnish    1 127.0.0.1:8081;  # panic-Varnish}

    Server-blokkiin:

    ❯ Näytä koodi
    set $panic 0;    if (-f /run/emergency_on) { set $panic 1; }    location / {        proxy_pass http://$varnish_upstream;...

    Varnishin kaatumisen ja nousun tunnistus

    Varnishin tilaa vahtii scripti varnish-switchover.sh:

    ❯ Näytä koodi
    #!/usr/bin/env bashset -euo pipefail# stop doing several ones at the same timeexec 9>/run/varnish_switchover.lockflock -n 9 || exit 0HEALTH_URL="http://127.0.0.1:8080/"EMER_FLAG="/run/emergency_on"OK_CNT="/run/varnish_ok.count"BAD_CNT="/run/varnish_bad.count"BAD_SINCE="/run/varnish_bad_since.ts"MIN_BAD_SEC=10# Checking if actual Varnish is healthyif varnishadm -T 127.0.0.1:6082 -S /etc/varnish/secret -t 1 ping >/dev/null 2>&1; then  healthy=1else  healthy=0fiinc()   { local f="$1"; local n=0; [[ -f "$f" ]] && n=$(cat "$f" 2>/dev/null || echo 0); echo $((n+1)) > "$f"; }reset() { : > "$1"; }if (( healthy )); then  # reseting “bad since”  [[ -f "$BAD_SINCE" ]] && rm -f "$BAD_SINCE"  # keep small hysteresis: 2 OK in the row before dropping the flag  inc "$OK_CNT"; reset "$BAD_CNT"  if (( $(cat "$OK_CNT") >= 2 )); then    [[ -f "$EMER_FLAG" ]] && rm -f "$EMER_FLAG"  fielse  # first BAD → mark startingtime (at this point Plesk get time to do its jobs, like post to Discourse)  if [[ ! -f "$BAD_SINCE" ]]; then    date +%s > "$BAD_SINCE"    reset "$OK_CNT"  fi  inc "$BAD_CNT"  bad_for=$(( $(date +%s) - $(cat "$BAD_SINCE" 2>/dev/null || echo 0) ))  # raise the flag when BAD has been at least MIN_BAD_SEC  if (( bad_for >= MIN_BAD_SEC )); then    [[ -f "$EMER_FLAG" ]] || touch "$EMER_FLAG"  fifi

    Se käyttää paria laskuria määrittelemään koska reagoidaan. Kun normaali Varnish ei vastaa kahteen kyselyyn peräkkäin, niin 10 sekunnin kuluttua asetetaan lippu /run/emergency_on . Sen löytyessä Nginx vaihtaa proxyksi paniikki-Varnishin.

    Scriptin kutsuu system-unit varnish-healthcheck.service :

    ❯ Näytä koodi
    [Unit]Description=Varnish healthcheck and switchover[Service]Type=oneshotExecStart=/usr/local/sbin/varnish-switchover.sh

    Sitä taasen ajastaa 5 sekunnin välein varnish-healthcheck.timer:

    ❯ Näytä koodi
    [Unit]Description=Run Varnish healthcheck every 30s[Timer]OnBootSec=10sOnUnitActiveSec=30sAccuracySec=1sUnit=varnish-healthcheck.service[Install]WantedBy=timers.target

    Aikaa voi toki muuttaa ja itse käytän hieman nopeasti reagoivaa.

    Paniikki-Varnish käynnistyy scriptillä varnish-panic.sh :

    ❯ Näytä koodi
    #!/usr/bin/env bash# Automatic panic handlingset -euo pipefailexec 9>/run/varnish-panic.lockflock -n 9 || { echo "panic varnish already running"; exit 0; }# Original:# varnishd -I /etc/varnish/start.cli.emerg -P /var/run/varnish.pid \#  -j unix,user=vcache -F -a :8080 -T localhost:6082 -f "" \#  -S /etc/varnish/secret -s malloc,256M/usr/sbin/varnishd \  -n panic \  -a 127.0.0.1:8081 \  -T 127.0.0.1:6083 \  -S /etc/varnish/secret \  -s malloc,256M \  -j unix,user=vcache \  -F \  -f '' \  -I /etc/varnish/start.cli.emerg

    Koska molemmat Varnishit ovat koko ajan yhtä aikaa käynnissä, niin

    • paniikki tarvitsee oman työhakemiston asetettuna -n lipulla
    • paniikki ei saa kuunnella samaa porttia Nginxin suuntaan kuin normaali
    • paniikki ei saa kuunnella backendiään samassa portissa kuin normaali
    • kommentoitu Original kohta toimii yksinään manuaalisena panic.sh ratkaisuna; kannattaa ajaa esim. tmuxissa

    Lisäksi paniikki tarvitsee oman käynnistystiedoston. Jos se käyttää samaa default.vcl tiedostoa tai vastaavaa, niin se kaatuu aivan samalla tavalla. Käyttämäni start.cli.emerg on:

    ❯ Näytä koodi
    vcl.load hot /etc/varnish/emergency.vclvcl.use hot

    Ja tarvittava emergency.vcl on perusmallinen vcl, joka määrittelee backendit ja asettaa return(pipe):. Löydät sen täältä:https://github.com/eksiscloud/Varnish7.x-multiplesites/blob/main/emergency.vcl

    Paniikki-Varnishin käynnistysscriptin pitää hengissä system-unit varnish-panic.service:

    ❯ Näytä koodi
    [Unit]Description=Varnish PANIC instance on :8081After=network-online.targetWants=network-online.target[Service]Type=simpleExecStart=/usr/local/bin/varnish-panic.shRestart=alwaysRestartSec=2sUser=rootGroup=root[Install]WantedBy=multi-user.target

    Omassa Ubuntussa systemd-yksiköt, service ja timer, löytyvät hakemistosta /etc/systemd/system/ ja scriptit olen tottunut laittamaan hakemistoon /usr/local/bin.

    Servicet ja timerit vaativat sekä systemctl daemon-reload kuin myös systemctl enable --now <nimi>. Scriptit muuttuvat ajettavaksi chmod +x <nimi>.

    Kaikki Varnishiin liittyvät löytyvät reposta https://github.com/eksiscloud/Varnish_7.x-multiple_sites

    #apache2 #nginx #valvonta #varnish

  14. Error 502 ja sivustojen backup-näyttö

    eksis.one/palvelimet/error-502

    Tuskin kukaan pitää tilanteesta, jossa selain esittää kliinisen kylmän error 500/502/503/504 virheen. Kävijät siksi, että eivät näe sisältöä. Ylläpito siksi, että 50x-sarjan virheet kertovat, että jokin serverillä on nurin, mutta ei anna pienintäkään viitettä syystä.

    Kertomattomuus johtuu siitä, että viallinen ei pysty kertomaan mihin sattuu, ja kuunteleva ei ymmärrä mistä on kyse.

    Omassa stackissa Nginx – Varnish – Apache2 (PHP, MariaDB, WordPress) virhekoodi saattaa antaa jotain suuntaa.

    • 500: Nginx tai virtuaalihostin konffi on rikki
    • 502: Varnish on kaatunut
    • 503: useimmiten Apache2 on kaatunut
    • 504: Apachen takana oleva WordPress on sekaisin

    Mutta tuohonkin on olemassa poikkeuksia ja kaikki riippuu siitä miten ongelmakohta pystyy vastaamaan pyyntöihin ja miten kyselijä ilmoituksen tulkitsee.

    Varajärjestelmän varajärjestelmä

    Olen kehittänyt 50x-sarjan virheistä itselleni eräänlaisen pakkomielteen. Osaksi koska inhoan niitä syvästi ja osaksi siksi, että pääsääntöisesti minä olen syypäänä onnistunut kaatamaan tai rikkomaan jotain. Aika harvoin ohjelmat itsessään hajoavat, vaikka niitäkin tapauksia on ollut.

    Katkokset ovat siten suolaa haavoihin hierova muistutus kädettömän sysadminin ammattitaidottomuudesta. Tai en tiedä voidaanko tällaisen kotitarveylläpitäjän kohdalla puhua ammattitaidottomuudesta. Kyse on pelkästään kyvyttömyydestä. Ja huolimattomuudestakin aika usein.

    Ongelman toinen puoli on se, että en aina tiedä suoraan miten virheen korjaan. Tunteja voi kulua, ja koko sen ajan jokainen sivusto on saavuttamattomissa. Joten tarvitsin mahdollisuuksien mukaan joko informatiivisemmat virhesivut tai jonkun backup-järjestelmän, joka esittää sisällön.

    Palapeli palapelin selässä

    Minulla työnkuva on useimmiten mallia on ongelma, etsin ensimmäisen ratkaisun, ongelma laajenee, etsin uuden ratkaisun, en tiedä mihin päädyn ja miten.

    50x-virheiden kohdalla tuo tarkoittaa sitä, että ensin lähdin säätämään virhesivuja. Niiden muuttaminen on aika triviaalia, mutta lisäinformaation saaminen ei ollut. Joten tyydyin vain muuttamaan tekstiä ja kerjäämään ihmisiä kertomaan, että sivustot ovat alhaalla.

    En yleensä saanut mitään tietoa kaatumisista, koska kaupalliset monitorit ovat kalliita ja ilmaiset ratkaisut aina jollain tapaa ongelmallisia.

    Joten seuraavaksi aloin selvittämään miten pystyisin saamaan tiedon minulle sopivalla tavalla, kun jokin palvelu ei tee sitä mitä sen kuuluisi. Olin aiemmin oivaltanut, että sellaista outoutta kuin API voidaan käyttää keskustelujen avaamiseen Discourse-foorumillani — ja se osaa lähettää push-ilmoituksia minulle.

    Joten ensin pienen ja sitä seuranneen isomman riidan jälkeen sain rakennettua tavan, jossa Nginx kertoo Plesk-serverille 50x-virheestä. Se taasen esittää kustomoidun virheilmoituksen ja avaa Discoursessa ketjun sille virheelle.

    Varnish tuuraa Apachea

    Siinä samalla oli alkanut itää ajatus esittää backup-sisältöä. Miksi tyytyä virheilmoituksiin, jos voisikin esittää edes jotain sisältöä.

    Helpointa, ainakin sillä hetkellä, oli keskittyä 503/504-virheisiin. Tilanteisiin, joissa Varnish käy ja kukkuu, mutta Apache2 tai WordPress on kaatunut. Helpointa siksi, että minullahan oli jo sisältö valmiina, ainakin osaksi: Varnishin cachessa. Se sisältö ei muutoinkaan koskaan piittaa backendistä; se on cachen pointti ja merkitys. Cache hyödyttää korvikesisältönä vain, jos cache lämmitetään, eli kaikki kopioidaan sinne. Se tavataan tehdä wgetillä — joka kykenee luomaan kohtuullisesti toimivan staattisen version sivustoista.

    Joten kun alkuperäinen tavoite oli vain lämmittää cache, niin olin tullut luoneeksi siinä ohessa snapshot-sisältöä. Tein siitä varajärjestelmän varajärjestelmän.

    Apache2/WordPress kaatuu. Niin kauan kun kukaan ei tee POST-kutsua tai pyydä sellaista, jota ei voida cachettaa, niin kukaan ei tiedä ongelmista mitään. Kaikki tulee 1:1 kopioina Varnishista.

    Varnish saa tiedon backendin hengettömyydestä, kun pyydetään sisältöä, jota ei löydy cachesta. Se vaihtaa backendiä ja hakeekin Nginxin kautta snapshot-sisällön, jos se on kelvollista (GET/HEAD) , tai esittää tympeän virheilmon (POST, admin jne.). Kyllä, olisin voinut tuottaa Nginxin kautta dynaamisen sisällön, mutta en lähtenyt sille tielle. En halua sählätä liikaa tietokannan kanssa. Jos se hajoaa, vaikka kaksoiskäytön takia, niin olen liian syvissä vesissä täysin uimataidottomana. Pelkään tietokantoja.

    Kun snapshot-sisältöön siirrytään, niin siitä menee tieto Pleskille, joka kertoo Discourselle, joka kertoo minulle.

    Samaan aikaan kävijät eivät tiedä mitään ongelmista, cachen takia, tai saavat ehkä hieman rikkinäisen, mutta käytettävän sisällön. Eivät jotain error-ilmoitusta.

    Kuka tuuraa Varnishia?

    Minulla useimmiten kaatuu Varnish. Ei sen takia, että se olisi epävakaa, vaan koska säädän sitä aina kun on liikaa vapaa-aikaa. Minun säätöni tapaavat olla aika riskialttiita. Joten tarvitsin jonkin turvajärjestelmän Varnishin kaatumisen varalta.

    Minulla on Nginx ja minulla on valmis snapshot-sisältö. En siis tarvinnut muuta kuin tavan tunnistaa 502-virhe, eli Varnishin kaatuminen, ja sen myötä kääntääkin proxy-liikenne uuteen suuntaan: snapshot-serverille, joka oli Nginxin hoivissa.

    Tässäkin vain staattiset kyselyt kelpasivat, koska tavoitteeni ei ollut milloinkaan rakentaa täysin toimivaa korvaajaa. Halusin tarjota jotain sisältöä virheilmoituksen sijaan.

    Sain sen rakennettua. Mutta minulla oli melkoisia ongelmia saada kävijät pois emergency-reitiltä takaisin normaaliin siinä vaiheessa, kun Varnish palasi linjoille.

    Tiesin entisestään, että mm. Bing ei piittaa 410 virheistä, tai redirect 301/302 erosta, vaan koputtelee maailman tappiin saakka kaikkea löytämäänsä. Päinvastoin kuin mitä Google selittää, niin samaa tekee osaltaan googlebot ja varsinkin google-image. Mutta minulle oli yllätys kuinka vähän laillisetkin botit piittasivat 302 käännön väliaikaisuudesta sekä cache-headereista, jotka ohjasivat olemaan tallentamatta sisältöä.

    Ne indeksoivatki suunnilleen kaiken ja väliaikaisiksi leimattuja emergency-polkuja alkoi löytymään hakutuloksista. Tuo ei ollut haluttua.

    Snapshot versio 2

    Nginxin serveriblokit alkoivat lisäksi olla melkoista sekasotkua. Oli mappia ja oli if-lausetta. Kaikki hyvin pitkälle siksi, että kun kävijän saaminen emergency-reitille ja snapshot-serverille ei ollut kovinkaan vaikeaa, niin en saanut selaimia pois hätäreitiltä, kun paniikki oli ohi.

    Javascriptillä toki olisi onnistunut, mutta siitä en tiedä mitään. En minä ole koodari. Minä olen kopypeistaaja.

    Riitelin taas kerran Nginxin kanssa tämän asian puitteissa. Olin sammuttanut Varnishin simuloidakseni Varnishin kaatumista ja koska normaalisti Varnish käynnistyy hitaasti, niin hyödynsin sen panic-toimintaa simulaationa tilanteen normalisoitumisessa. Se kun käynnistyy silmänräpäyksessä.

    Minulla on panic-scripti tilanteita varten, jossa Varnish kaatuu, ja tiedän korjauksen vievän aikaa. Siinä master ohitetaan CLI:n avulla. Joten jos Varnishin ytimessä henki pihisee, niin saan sen käyntiin. Toki menetän cachen ja sellaisia asioita, mutta sivustoille pääsee Varnishin ollessa vain tyhmä putki.

    Jäin testeissäni ihmettelemään mitä olin juuri tehnyt. Olin käynnistänyt tmuxin, koska CLI täytyy olla koko ajan käynnissä, ja potkaissut Varnishin prosessin käyntiin. Mutta virallisestihan Varnish oli edelleen naamallaan, ja sehän on juurikin se tilanne, jonka hätätoimintoa yritin Nginxillä rakentaa.

    Olen tehnyt tuon ennenkin, monta kertaa. Kuten kun sekoilin kääntämisessä, ja rikoin Varnishin, niin pyöritin sitä tmuxin sisällä CLI:n kautta lähes viikon. Joten… miksi en tekisi samaa nyt, mutta ilman tmuxia ja automatisoituna, jolloin minun ei tarvitse riidellä niin paljon emergency-polun kanssa.

    Puolikkaan työpäivän ja useiden kokeilujen ja erehdysten jälkeen minulla on nyt järjestelmä, jossa Varnishin kaatuessa 10 sekunnin ajan esitetään virheilmoitus ja pyydetään kävijältä reload (tuo viive on Pleskin takia, luultavasti 5 sekuntiakin riittäisi varnistamaan, että API-pyyntö lähtee Discourseen).

    Seuraavaksi käynnistetään Varnish CLI-malliin mutta automaattisesti scriptillä. Taustalla käydään kyselemässä aika ajoin onko aito Varnish vihdoin järjissään ja kun se on käynnistynyt, niin vaihdetaan paniikki-Varnishista aitoon normaaliin Varnishiin.

    Eikä kukaan huomaa mitään — paitsi sen ensimmäisen 10 sekunnin ajan.

    Mutta… jos Varnish kaatuu oikeasti?

    Tuo järjestelmä ei ole todellakaan aukoton. Kaikkea muuta. Mutta noin 98 kertaa sadasta Varnishin kaatuminen on sellainen, että uusi instanssi saadaan käynnistettyä.

    Jos Varnish on täysin kuollut, niin sille ei ole varsinaista varajärjestelmää. Snapshot-serverin emergency ei onnistu minun taidoillani. Se hemmetin emergency-polku pysyy siellä, kiitos selainten. Ja koska moinen päätyy hakukoneisiin, niin en käytä sitä. Esitän mieluummin virheilmoitusta.

    Lisään emergencyn polkuun kahdesta syystä. Ensimmäinen on, että sillä estän wgetin muokkaaman (ja hieman rikkoman) sisällön saastuttamasta aitoa cachea. Toinen syy on, että silloin urista näkee, että ei olla normaalitilanteessa.

    Jos backend on saavuttamattomissa, niin Varnish ja Nginx käyttävät cacheamattoman sisällön kohdalla emergency-polkua. Mutta cachen lämmitys on noin 95 prosenttisen tehokas, joten se tulee käyttöön erittäin harvoin. Kun tulee, niin Varnish siivoaa emergemcy-osan pois vastauksesta tilanteen normalisoiduttua.

    Ihmiset näkevät emergencyn urlissa korjaantumisen jälkeenkin, paitsi jos klikkaavat jotain uutta linkkiä — merkintä lisätään Nginxissä, ei snapshotteihin — mutta botit näkevät polun oikein oikeilla headereilla. Eikä ihmisistä ole väliä, koska selaimethan eivät enää edes varsinaisesti näytä urlia.

    Mutta jos Varnish on totaalisen kuollut, niin laitan Nginxin juttelemaan suoraan Apachen kanssa. Se on vielä manuaalinen säätö, mutta tiedän miten sen saisi semiautomaattiseksi — ehkä teen sen muutoksen, kun taas on hieman liikaa vapaa-aikaa.

    Varajärjestelmä tämä kirjoitettaessa

    Jos backend kaatuu, niin Varnish käyttää cachea tai ohjaa Nginxin kautta snapshot-sisältöön.

    Jos Varnish kaatuu, niin käynnistetään toisenlainen Varnish, joka keskustelee suoraan backendin kanssa.

    Jos Varnish kaatuu totaalisesti, niin pakotan manuaalisesti Nginxin juttelemaan Apachen kanssa.

    Jos Nginx kaatuu… tuota en ole vielä tehnyt, mutta minulla on alustava konsepti. Ehkä saisin Hitchin tai muun SSL/TSL-terminaattorin hoitamaan saapuvan liikenteen ja kääntäisin sen tyhmälle paniikki-Varnishille.

    Miten koostin nykyisen Varnish korvaa Varnishin?

    Alleviivaan jo mainittua: en ole koodari. Tämän olisi varmaan voinut tehdä helpomminkin, mutta minä en tätä kummallisempaan kyennyt.

    Nginx kääntää uudelle proxylle:

    Ennen server-blokkia (käytä omia porttejasi):

    ❯ Näytä koodi
    [map $panic $varnish_upstream ](#)    0 127.0.0.1:8080;  # normaali Varnish    1 127.0.0.1:8081;  # panic-Varnish}

    Server-blokkiin:

    ❯ Näytä koodi
    set $panic 0;    if (-f /run/emergency_on) { set $panic 1; }    location / {        proxy_pass http://$varnish_upstream;...

    Varnishin kaatumisen ja nousun tunnistus

    Varnishin tilaa vahtii scripti varnish-switchover.sh:

    ❯ Näytä koodi
    #!/usr/bin/env bashset -euo pipefail# stop doing several ones at the same timeexec 9>/run/varnish_switchover.lockflock -n 9 || exit 0HEALTH_URL="http://127.0.0.1:8080/"EMER_FLAG="/run/emergency_on"OK_CNT="/run/varnish_ok.count"BAD_CNT="/run/varnish_bad.count"BAD_SINCE="/run/varnish_bad_since.ts"MIN_BAD_SEC=10# Checking if actual Varnish is healthyif varnishadm -T 127.0.0.1:6082 -S /etc/varnish/secret -t 1 ping >/dev/null 2>&1; then  healthy=1else  healthy=0fiinc()   { local f="$1"; local n=0; [[ -f "$f" ]] && n=$(cat "$f" 2>/dev/null || echo 0); echo $((n+1)) > "$f"; }reset() { : > "$1"; }if (( healthy )); then  # reseting “bad since”  [[ -f "$BAD_SINCE" ]] && rm -f "$BAD_SINCE"  # keep small hysteresis: 2 OK in the row before dropping the flag  inc "$OK_CNT"; reset "$BAD_CNT"  if (( $(cat "$OK_CNT") >= 2 )); then    [[ -f "$EMER_FLAG" ]] && rm -f "$EMER_FLAG"  fielse  # first BAD → mark startingtime (at this point Plesk get time to do its jobs, like post to Discourse)  if [[ ! -f "$BAD_SINCE" ]]; then    date +%s > "$BAD_SINCE"    reset "$OK_CNT"  fi  inc "$BAD_CNT"  bad_for=$(( $(date +%s) - $(cat "$BAD_SINCE" 2>/dev/null || echo 0) ))  # raise the flag when BAD has been at least MIN_BAD_SEC  if (( bad_for >= MIN_BAD_SEC )); then    [[ -f "$EMER_FLAG" ]] || touch "$EMER_FLAG"  fifi

    Se käyttää paria laskuria määrittelemään koska reagoidaan. Kun normaali Varnish ei vastaa kahteen kyselyyn peräkkäin, niin 10 sekunnin kuluttua asetetaan lippu /run/emergency_on . Sen löytyessä Nginx vaihtaa proxyksi paniikki-Varnishin.

    Scriptin kutsuu system-unit varnish-healthcheck.service :

    ❯ Näytä koodi
    [Unit]Description=Varnish healthcheck and switchover[Service]Type=oneshotExecStart=/usr/local/sbin/varnish-switchover.sh

    Sitä taasen ajastaa 5 sekunnin välein varnish-healthcheck.timer:

    ❯ Näytä koodi
    [Unit]Description=Run Varnish healthcheck every 30s[Timer]OnBootSec=10sOnUnitActiveSec=30sAccuracySec=1sUnit=varnish-healthcheck.service[Install]WantedBy=timers.target

    Aikaa voi toki muuttaa ja itse käytän hieman nopeasti reagoivaa.

    Paniikki-Varnish käynnistyy scriptillä varnish-panic.sh :

    ❯ Näytä koodi
    #!/usr/bin/env bash# Automatic panic handlingset -euo pipefailexec 9>/run/varnish-panic.lockflock -n 9 || { echo "panic varnish already running"; exit 0; }# Original:# varnishd -I /etc/varnish/start.cli.emerg -P /var/run/varnish.pid \#  -j unix,user=vcache -F -a :8080 -T localhost:6082 -f "" \#  -S /etc/varnish/secret -s malloc,256M/usr/sbin/varnishd \  -n panic \  -a 127.0.0.1:8081 \  -T 127.0.0.1:6083 \  -S /etc/varnish/secret \  -s malloc,256M \  -j unix,user=vcache \  -F \  -f '' \  -I /etc/varnish/start.cli.emerg

    Koska molemmat Varnishit ovat koko ajan yhtä aikaa käynnissä, niin

    • paniikki tarvitsee oman työhakemiston asetettuna -n lipulla
    • paniikki ei saa kuunnella samaa porttia Nginxin suuntaan kuin normaali
    • paniikki ei saa kuunnella backendiään samassa portissa kuin normaali
    • kommentoitu Original kohta toimii yksinään manuaalisena panic.sh ratkaisuna; kannattaa ajaa esim. tmuxissa

    Lisäksi paniikki tarvitsee oman käynnistystiedoston. Jos se käyttää samaa default.vcl tiedostoa tai vastaavaa, niin se kaatuu aivan samalla tavalla. Käyttämäni start.cli.emerg on:

    ❯ Näytä koodi
    vcl.load hot /etc/varnish/emergency.vclvcl.use hot

    Ja tarvittava emergency.vcl on perusmallinen vcl, joka määrittelee backendit ja asettaa return(pipe):. Löydät sen täältä:https://github.com/eksiscloud/Varnish7.x-multiplesites/blob/main/emergency.vcl

    Paniikki-Varnishin käynnistysscriptin pitää hengissä system-unit varnish-panic.service:

    ❯ Näytä koodi
    [Unit]Description=Varnish PANIC instance on :8081After=network-online.targetWants=network-online.target[Service]Type=simpleExecStart=/usr/local/bin/varnish-panic.shRestart=alwaysRestartSec=2sUser=rootGroup=root[Install]WantedBy=multi-user.target

    Omassa Ubuntussa systemd-yksiköt, service ja timer, löytyvät hakemistosta /etc/systemd/system/ ja scriptit olen tottunut laittamaan hakemistoon /usr/local/bin.

    Servicet ja timerit vaativat sekä systemctl daemon-reload kuin myös systemctl enable --now <nimi>. Scriptit muuttuvat ajettavaksi chmod +x <nimi>.

    Kaikki Varnishiin liittyvät löytyvät reposta https://github.com/eksiscloud/Varnish_7.x-multiple_sites

    #apache2 #nginx #valvonta #varnish

  15. BLE YN Y BYD? :
    WHERE IN THE WORLD is #Abercarn?

    Between Blackwood and Pontypool, see:

    openstreetmap.cymru?h=51.64955
    @mapioCymru @openstreetmap

    Thankfully, today they play #DP40s @ StCyresSchool 2.30pm

    #DinasPowys #Vets 🐯
    vs AbercarnOver40s AKA The Stuffers! Well it is nearly Xmas…

    🦃

  16. Z80 and AY-3-8910 – Part 2

    I’ve spent a bit of time looking at the “Tester” part of the AY driver code for Tim Follin’s music archive that I talked about in Z80 and AY-3-8910.

    This is documenting what I think I’ve worked out so far for the tester code.

    The Sound Tester

    As previously mentioned, there are essentially three parts to the code in Follin archive:

    • The tune and effect data.
    • Ste Ruddy’s Sound Driver.
    • A tracker-style (ish) tester UI application.

    The first part looked at the sound driver itself, and essentially skipped over the tester part of the code. This post picks up on that tester code.

    Reminder, from part one, the main structure is as follows:

    Code_Start: EQU 40000
    Data_Start: EQU 50000

    ;-----------------------------
    ORG Code_Start

    ; The UI/tester code
    TESTER:
    LOOP: Calls the following for each scan:
    HALT - Suspends until an interrupt comes in?
    CALL UPDATE
    CALL REFRESH
    CALL CLOCK
    CALL KEYSCAN
    Repeat as necessary

    KEYSCAN: UI scanning
    CLOCK: Possibly maintain a 50Hz refresh rate clock?
    UPDATE: Loads the internal state of all sound variables from
    the driver and displays them in real time via the UI.

    ; The sound driver
    CODE_TOP:
    TUNE: Select which tune to play.
    TUNE_IN: Init all internal sound state variables for a new tune.
    TUNEOFF: Stop a playing tune, eg to change tune or start an FX.

    FX: Start playing an FX.
    FLOOP: Keep processing FX instructions until complete.

    REFRESH: "run" a scan of the sound driver updating and outputting the sound

    The Tester Code

    Initialisation information and main screen data:

    ;**************************************

    ; Z80 AY MUSIC DRIVER

    ;**************************************

    ; ORG 40000
    ; LOAD 0C000H

    ;======================================
    ;STACK DEPTHS

    SD: EQU 3

    ;======================================

    ASCII: EQU 23560 ; 23560 = $5C08 = System Variable "LAST K"

    TESTER: PUSH AF
    PUSH BC
    PUSH DE
    PUSH HL

    XOR A ; ASCII = MINS = SECS = 0
    LD (ASCII),A
    LD (MINS),A
    LD (SECS),A

    CALL TUNEOFF ; TUNE initialisation
    CALL STACKMESS ; Kick off the Tester code!

    DB CLS ; The start of the main UI data
    DB AT,0,0
    DB INK,01010111B
    DB "'AY' MUSIC DRIVE"
    DB "R V2 BY S.RUDDY"

    ... Skip ...

    DB INK,64+5
    DB "VOLUME "
    DB " "
    DB 255

    ... Skip ...

    AT: EQU 22
    INK: EQU 16
    CLS: EQU 15

    STACKMESS: POP IX
    CALL MESS
    JP (IX)

    There is a whole lot of screen data in DB blocks which includes some “op codes” that are defined later: AT, INK, CLS. These are special codes that are used by the ROM-based print routines (more here), as used by Sinclair BASIC, but in this case they are spelt out directly, later in code. The final 255 signifies the end of the screen data.

    So how are these definitions handled? That all comes up in the “MESS” routine I’ll get to in a moment, but first that “STACKMESS” routine needs a bit of explanation.

    When a CALL instruction happens, such as the CALL STACKMESS at the start, the current program counter gets pushed onto the stack. In this case the current PC will point to the instruction after the CALL, which happens to be the start of the screen data. So the POP IX will grab the address of the screen data and drop it into IX and then call the “MESS” function to actually get on with it!

    But before I get to that, there is some more code after the screen data:

                    LD HL,CALC1
    PUSH HL
    LD A,H
    LD DE,4067H ; Output high byte
    CALL HEX
    POP HL
    LD A,L
    LD DE,4069H ; Output low byte
    CALL HEX

    LD HL,(CALC2)
    PUSH HL
    LD A,H
    LD DE,4071H ; Output number of Tunes
    CALL HEX
    POP HL
    LD A,L
    LD DE,4073H ; Output number of effects
    CALL HEX

    LD HL,CALC1
    LD DE,(CALC2)
    ADD HL,DE
    PUSH HL
    LD A,H
    LD DE,407CH ; Not entirely sure what this is outputting...
    CALL HEX
    POP HL
    LD A,L
    LD DE,407EH
    CALL HEX

    This is writing some basic data out to the display. CALC1 seems to relate to code section size. I believe CALC2 is the start address of the tune data, which is the following:

                    ORG Data_Start

    TUNES: EQU 5
    EFFECTS: EQU 21

    All three of these sections are outputting a 16-bit value in two single-byte chunks using the “HEX” routine, which takes a screen address (in the range $4000-$57FF) and outputs a hex number at that screen location.

    So while I’m at it then, how is that HEX function working?

    ;--------------------------------------
    HEX: INC DE ; DE contains the screen address to use
    PUSH AF ; Start with DE+1
    CALL ONEnib ; Write out the LOW 4-bits
    POP AF
    RRA ; A = A>>4
    RRA ; to write out HIGH 4-bits
    RRA
    RRA
    DEC DE ; Back to original DE screen address
    ONEnib: AND 15 ; A = A & 0xF
    ADD A ; BC = A * 2
    LD C,A
    LD B,0
    LD HL,ROM_TAB ; Read from ROM_TAB[BC]
    ADD HL,BC
    LD A,(HL)
    INC HL
    LD H,(HL)
    LD L,A ; HL = (uint16_t)ROM_TAB[A]
    MIKESbug: LD C,D ; So HL now points to character bitmap in ROM
    LD B,8 ; Write out 8 bytes to display memory directly
    PRloop: LD A,(HL) ; (DE) = (HL)
    LD (DE),A
    INC HL ; HL++
    INC D ; NB: Layout of display mem means D++ is next line of char
    ; for same value of E.
    DJNZ PRloop ; WHILE (B-- > 0)
    LD D,C ; (Restore D before returning, so DE still = screen addr)
    RET

    ROM_TAB: DW 3D80H ; ROM character set: 3D80 = "0"
    DW 3D88H ; Each char = 8 x 8 bits
    DW 3D90H
    DW 3D98H
    DW 3DA0H
    DW 3DA8H
    DW 3DB0H
    DW 3DB8H
    DW 3DC0H
    DW 3DC8H ; = "9"
    DW 3E08H ; = "A"
    DW 3E10H
    DW 3E18H
    DW 3E20H
    DW 3E28H
    DW 3E30H ; = "F"

    This is making use of the character set stored in the Spectrum ROM (more here) which is indexed via a 16-word jump table mapping the characters onto each of the 16 hex characters: 0..9, A..F.

    Then each byte, 8 in total, of the character is written directly out to the Spectrum screen memory taking advantage of the odd formatting of the screen memory to easily skip to the next line of the display for each line of the character (more here).

    So before I get into the main update loop, how the screen initialised and set up? That happens in the “MESS” and some ancillary functions.

    MESS:           LD A,(IX+0)         ; At this point, McursorX, McursorY = (0,0)
    INC IX ; So read a byte of screen data
    OR A
    RET M ; Stop IF A=255 (i.e. negative)
    CP 32
    JR C,Mcontrol ; IF A<32 process control character then RET back to "MESS"
    CALL Mgetchar ; ELSE Process character
    CALL Mgetaddr ; Get screen address for next output in DE
    CALL MIKESbug ; Output the character
    CALL PRattr ; Set the colour attributes
    CALL INCcursor ; Update the screen position for the next byte of screen data
    JR MESS

    Mcontrol: LD HL,MESS ; Stick the address of "MESS" on the stack for the RET
    PUSH HL
    CP 15 ; IF A == CLS
    JR Z,Mcls
    CP 22 ; IF A == AT
    JP Z,Mat
    CP 16 ; IF A == INK
    JR Z,Mink
    RET ; RETurn to "MESS"

    Mcolour: DB 0 ; Working variables for cursor position and colour
    McursorX: DB 0
    McursorY: DB 0 ; Has to be directly after McursorX (see later)

    Mink: LD A,(IX+0) ; Process INK to set colour
    INC IX
    LD (Mcolour),A
    RET

    Mcls: LD HL,4000H ; Process CLS to clear screen
    LD (HL),L
    LD DE,4001H
    LD BC,1AFFH
    LDIR
    LD (McursorX),BC
    RET

    INCcursor: LD HL,McursorX ; Moves the cursor on one position
    LD A,(HL)
    INC A
    AND 31
    LD (HL),A ; X++; X = X % 32
    RET NZ ; IF X==0; Y++
    INC HL ; Assumes McursorY is McursorX++
    INC (HL)
    RET

    Mgetchar: LD L,A ; HL = A*8 + 3C00
    LD H,0 ; Note: A > 32; where 32="Space"
    ADD HL,HL ; In ROM, space is address 3D00
    ADD HL,HL ; 32 * 8 = 0x100
    ADD HL,HL
    LD BC,3C00H
    ADD HL,BC ; HL = Start address of character map for char in A in ROM
    RET

    .... skip ....

    Mgetaddr: LD A,(McursorY) ; Calculate the screen address for (McursorX, McursorY)
    AND 18H
    OR 40H
    LD D,A
    LD A,(McursorY)
    RRCA
    RRCA
    RRCA
    AND 0E0H
    LD E,A
    LD A,(McursorX)
    ADD E
    LD E,A
    RET ; DE = required screen address

    Mat: LD A,(IX+0) ; Set cursor to provided X, Y in screen data
    LD (McursorX),A
    INC IX
    LD A,(IX+0)
    LD (McursorY),A
    INC IX
    RET

    PRattr: LD A,D ; Get address of ATTRibute memory
    RRA
    RRA
    RRA
    AND 3
    OR 58H
    LD D,A
    LD A,(Mcolour)
    LD (DE),A ; And set the colour
    RET

    Basically this loop keeps working on the provided screen data until the value 255 is found, at which point it returns. There are two paths for handling the data:

    • IF the value is < 32 then it is a control value. Only CLS, AT and INK are recognised.
    • ELSE the value is assumed to be an ASCII character and is displayed.

    Whatever is happening, happens at the coordinates given by (McursorX, McursorY) which start out as (0,0) and get updated automatically when a character is output, or in response to an AT command. INK will set the required colour in Mcolour, which again starts out as 0. This is applied after the character is written to the screen, using the PRattr function.

    There is a fun bit of optimisation going on in Mcontrol. At the start it pushes the address of the MESS function on the stack, which means that the RET will jump back to the start of MESS rather than where the jump happened to Mcontrol itself.

    There is another shortcut in the Mcls function: LDIR. From http://z80-heaven.wikidot.com/instructions-set:ldir: “Repeats LDI (LD (DE),(HL), then increments DE, HL, and decrements BC) until BC=0.” By setting the contents of HL (the first byte of the display) to zero, this will tile that same value across the display memory until BC, which starts at $1AFF, is zero. This will zero the whole display – both pixels and attributes – from 0x4000 through to 0x5AFF.

    Now finally, we get to the main update loop.

    LOOP:           
    HALT
    CALL UPDATE ; Update the display from the current Sound parameters
    LD A,2
    OUT (254),A ; Set border to 2
    CALL REFRESH ; Update the sound driver parameters
    XOR A
    OUT (254),A ; Set border to 0
    CALL CLOCK ; Run 50Hz clock
    CALL KEYSCAN ; Guess what - scans the keyboard 🙂
    LD A,07FH
    IN A,(254) ; Reads 0x7FFE which is the bottom row of the keyboard
    AND 1
    JP NZ,LOOP ; Checks bit 0, which is the SPACE key
    LD BC,65533 ; AY OUTPUT PORTS (FFFD, BFFD)
    LD A,7
    OUT (C),A
    LD BC,49149
    LD A,63 ; Set AY register 7 to 63 - i.e. all channels OFF
    OUT (C),A

    POP HL
    POP DE
    POP BC
    POP AF
    RET

    I’m not going through the sub routines of the loop, other than to note the following:

    • UPDATE is a whole series of instructions that basically do the following to output the HEX value of a sound parameter:
    LD A, (contents of one of the sound variables)
    LD DE, (corresponding screen address for the variable to be displayed)
    CALL HEX
    • REFRESH runs the sound driver itself, as described in Z80 and AY-3-8910.
    • CLOCK decrements the FIFTY variable and every time it gets to zero updates SECS and MINS and writes them out to the display. As it also uses the HEX routine, I guess it is storing the time using binary-coded decimal (BCD).
    • KEYSCAN reads the last key pressed from the system variable location stored in ASCII (23560 / 0x5C08).

    At some point I might come back and work out what keys do what…

    Closing Thoughts

    I’d really like to get some of this code running on some of the alternate Z80 platforms I have. Getting the sound output shouldn’t be too much of an issue, but I’d really like to have some kind of display too.

    But as can be seen above, the tester UI is pretty well tied into the oddities of the ZX Spectrum display, so porting it won’t be trivial.

    I suspect there are already some existing AY/chiptune players that perhaps would be a better starting point, but from what I’ve seen they tend to stream the register data after having sampled it at regular intervals, which isn’t quite what I was after… there would be something really quite interesting about actually running Ste Ruddy’s Sound Driver with a Tim Follin soundtrack programmed in.

    Kevin

    #ay38910 #TimFollin #zxSpectrum
  17. Z80 and AY-3-8910 – Part 2

    I’ve spent a bit of time looking at the “Tester” part of the AY driver code for Tim Follin’s music archive that I talked about in Z80 and AY-3-8910.

    This is documenting what I think I’ve worked out so far for the tester code.

    The Sound Tester

    As previously mentioned, there are essentially three parts to the code in Follin archive:

    • The tune and effect data.
    • Ste Ruddy’s Sound Driver.
    • A tracker-style (ish) tester UI application.

    The first part looked at the sound driver itself, and essentially skipped over the tester part of the code. This post picks up on that tester code.

    Reminder, from part one, the main structure is as follows:

    Code_Start: EQU 40000
    Data_Start: EQU 50000

    ;-----------------------------
    ORG Code_Start

    ; The UI/tester code
    TESTER:
    LOOP: Calls the following for each scan:
    HALT - Suspends until an interrupt comes in?
    CALL UPDATE
    CALL REFRESH
    CALL CLOCK
    CALL KEYSCAN
    Repeat as necessary

    KEYSCAN: UI scanning
    CLOCK: Possibly maintain a 50Hz refresh rate clock?
    UPDATE: Loads the internal state of all sound variables from
    the driver and displays them in real time via the UI.

    ; The sound driver
    CODE_TOP:
    TUNE: Select which tune to play.
    TUNE_IN: Init all internal sound state variables for a new tune.
    TUNEOFF: Stop a playing tune, eg to change tune or start an FX.

    FX: Start playing an FX.
    FLOOP: Keep processing FX instructions until complete.

    REFRESH: "run" a scan of the sound driver updating and outputting the sound

    The Tester Code

    Initialisation information and main screen data:

    ;**************************************

    ; Z80 AY MUSIC DRIVER

    ;**************************************

    ; ORG 40000
    ; LOAD 0C000H

    ;======================================
    ;STACK DEPTHS

    SD: EQU 3

    ;======================================

    ASCII: EQU 23560 ; 23560 = $5C08 = System Variable "LAST K"

    TESTER: PUSH AF
    PUSH BC
    PUSH DE
    PUSH HL

    XOR A ; ASCII = MINS = SECS = 0
    LD (ASCII),A
    LD (MINS),A
    LD (SECS),A

    CALL TUNEOFF ; TUNE initialisation
    CALL STACKMESS ; Kick off the Tester code!

    DB CLS ; The start of the main UI data
    DB AT,0,0
    DB INK,01010111B
    DB "'AY' MUSIC DRIVE"
    DB "R V2 BY S.RUDDY"

    ... Skip ...

    DB INK,64+5
    DB "VOLUME "
    DB " "
    DB 255

    ... Skip ...

    AT: EQU 22
    INK: EQU 16
    CLS: EQU 15

    STACKMESS: POP IX
    CALL MESS
    JP (IX)

    There is a whole lot of screen data in DB blocks which includes some “op codes” that are defined later: AT, INK, CLS. These are special codes that are used by the ROM-based print routines (more here), as used by Sinclair BASIC, but in this case they are spelt out directly, later in code. The final 255 signifies the end of the screen data.

    So how are these definitions handled? That all comes up in the “MESS” routine I’ll get to in a moment, but first that “STACKMESS” routine needs a bit of explanation.

    When a CALL instruction happens, such as the CALL STACKMESS at the start, the current program counter gets pushed onto the stack. In this case the current PC will point to the instruction after the CALL, which happens to be the start of the screen data. So the POP IX will grab the address of the screen data and drop it into IX and then call the “MESS” function to actually get on with it!

    But before I get to that, there is some more code after the screen data:

                    LD HL,CALC1
    PUSH HL
    LD A,H
    LD DE,4067H ; Output high byte
    CALL HEX
    POP HL
    LD A,L
    LD DE,4069H ; Output low byte
    CALL HEX

    LD HL,(CALC2)
    PUSH HL
    LD A,H
    LD DE,4071H ; Output number of Tunes
    CALL HEX
    POP HL
    LD A,L
    LD DE,4073H ; Output number of effects
    CALL HEX

    LD HL,CALC1
    LD DE,(CALC2)
    ADD HL,DE
    PUSH HL
    LD A,H
    LD DE,407CH ; Not entirely sure what this is outputting...
    CALL HEX
    POP HL
    LD A,L
    LD DE,407EH
    CALL HEX

    This is writing some basic data out to the display. CALC1 seems to relate to code section size. I believe CALC2 is the start address of the tune data, which is the following:

                    ORG Data_Start

    TUNES: EQU 5
    EFFECTS: EQU 21

    All three of these sections are outputting a 16-bit value in two single-byte chunks using the “HEX” routine, which takes a screen address (in the range $4000-$57FF) and outputs a hex number at that screen location.

    So while I’m at it then, how is that HEX function working?

    ;--------------------------------------
    HEX: INC DE ; DE contains the screen address to use
    PUSH AF ; Start with DE+1
    CALL ONEnib ; Write out the LOW 4-bits
    POP AF
    RRA ; A = A>>4
    RRA ; to write out HIGH 4-bits
    RRA
    RRA
    DEC DE ; Back to original DE screen address
    ONEnib: AND 15 ; A = A & 0xF
    ADD A ; BC = A * 2
    LD C,A
    LD B,0
    LD HL,ROM_TAB ; Read from ROM_TAB[BC]
    ADD HL,BC
    LD A,(HL)
    INC HL
    LD H,(HL)
    LD L,A ; HL = (uint16_t)ROM_TAB[A]
    MIKESbug: LD C,D ; So HL now points to character bitmap in ROM
    LD B,8 ; Write out 8 bytes to display memory directly
    PRloop: LD A,(HL) ; (DE) = (HL)
    LD (DE),A
    INC HL ; HL++
    INC D ; NB: Layout of display mem means D++ is next line of char
    ; for same value of E.
    DJNZ PRloop ; WHILE (B-- > 0)
    LD D,C ; (Restore D before returning, so DE still = screen addr)
    RET

    ROM_TAB: DW 3D80H ; ROM character set: 3D80 = "0"
    DW 3D88H ; Each char = 8 x 8 bits
    DW 3D90H
    DW 3D98H
    DW 3DA0H
    DW 3DA8H
    DW 3DB0H
    DW 3DB8H
    DW 3DC0H
    DW 3DC8H ; = "9"
    DW 3E08H ; = "A"
    DW 3E10H
    DW 3E18H
    DW 3E20H
    DW 3E28H
    DW 3E30H ; = "F"

    This is making use of the character set stored in the Spectrum ROM (more here) which is indexed via a 16-word jump table mapping the characters onto each of the 16 hex characters: 0..9, A..F.

    Then each byte, 8 in total, of the character is written directly out to the Spectrum screen memory taking advantage of the odd formatting of the screen memory to easily skip to the next line of the display for each line of the character (more here).

    So before I get into the main update loop, how the screen initialised and set up? That happens in the “MESS” and some ancillary functions.

    MESS:           LD A,(IX+0)         ; At this point, McursorX, McursorY = (0,0)
    INC IX ; So read a byte of screen data
    OR A
    RET M ; Stop IF A=255 (i.e. negative)
    CP 32
    JR C,Mcontrol ; IF A<32 process control character then RET back to "MESS"
    CALL Mgetchar ; ELSE Process character
    CALL Mgetaddr ; Get screen address for next output in DE
    CALL MIKESbug ; Output the character
    CALL PRattr ; Set the colour attributes
    CALL INCcursor ; Update the screen position for the next byte of screen data
    JR MESS

    Mcontrol: LD HL,MESS ; Stick the address of "MESS" on the stack for the RET
    PUSH HL
    CP 15 ; IF A == CLS
    JR Z,Mcls
    CP 22 ; IF A == AT
    JP Z,Mat
    CP 16 ; IF A == INK
    JR Z,Mink
    RET ; RETurn to "MESS"

    Mcolour: DB 0 ; Working variables for cursor position and colour
    McursorX: DB 0
    McursorY: DB 0 ; Has to be directly after McursorX (see later)

    Mink: LD A,(IX+0) ; Process INK to set colour
    INC IX
    LD (Mcolour),A
    RET

    Mcls: LD HL,4000H ; Process CLS to clear screen
    LD (HL),L
    LD DE,4001H
    LD BC,1AFFH
    LDIR
    LD (McursorX),BC
    RET

    INCcursor: LD HL,McursorX ; Moves the cursor on one position
    LD A,(HL)
    INC A
    AND 31
    LD (HL),A ; X++; X = X % 32
    RET NZ ; IF X==0; Y++
    INC HL ; Assumes McursorY is McursorX++
    INC (HL)
    RET

    Mgetchar: LD L,A ; HL = A*8 + 3C00
    LD H,0 ; Note: A > 32; where 32="Space"
    ADD HL,HL ; In ROM, space is address 3D00
    ADD HL,HL ; 32 * 8 = 0x100
    ADD HL,HL
    LD BC,3C00H
    ADD HL,BC ; HL = Start address of character map for char in A in ROM
    RET

    .... skip ....

    Mgetaddr: LD A,(McursorY) ; Calculate the screen address for (McursorX, McursorY)
    AND 18H
    OR 40H
    LD D,A
    LD A,(McursorY)
    RRCA
    RRCA
    RRCA
    AND 0E0H
    LD E,A
    LD A,(McursorX)
    ADD E
    LD E,A
    RET ; DE = required screen address

    Mat: LD A,(IX+0) ; Set cursor to provided X, Y in screen data
    LD (McursorX),A
    INC IX
    LD A,(IX+0)
    LD (McursorY),A
    INC IX
    RET

    PRattr: LD A,D ; Get address of ATTRibute memory
    RRA
    RRA
    RRA
    AND 3
    OR 58H
    LD D,A
    LD A,(Mcolour)
    LD (DE),A ; And set the colour
    RET

    Basically this loop keeps working on the provided screen data until the value 255 is found, at which point it returns. There are two paths for handling the data:

    • IF the value is < 32 then it is a control value. Only CLS, AT and INK are recognised.
    • ELSE the value is assumed to be an ASCII character and is displayed.

    Whatever is happening, happens at the coordinates given by (McursorX, McursorY) which start out as (0,0) and get updated automatically when a character is output, or in response to an AT command. INK will set the required colour in Mcolour, which again starts out as 0. This is applied after the character is written to the screen, using the PRattr function.

    There is a fun bit of optimisation going on in Mcontrol. At the start it pushes the address of the MESS function on the stack, which means that the RET will jump back to the start of MESS rather than where the jump happened to Mcontrol itself.

    There is another shortcut in the Mcls function: LDIR. From http://z80-heaven.wikidot.com/instructions-set:ldir: “Repeats LDI (LD (DE),(HL), then increments DE, HL, and decrements BC) until BC=0.” By setting the contents of HL (the first byte of the display) to zero, this will tile that same value across the display memory until BC, which starts at $1AFF, is zero. This will zero the whole display – both pixels and attributes – from 0x4000 through to 0x5AFF.

    Now finally, we get to the main update loop.

    LOOP:           
    HALT
    CALL UPDATE ; Update the display from the current Sound parameters
    LD A,2
    OUT (254),A ; Set border to 2
    CALL REFRESH ; Update the sound driver parameters
    XOR A
    OUT (254),A ; Set border to 0
    CALL CLOCK ; Run 50Hz clock
    CALL KEYSCAN ; Guess what - scans the keyboard 🙂
    LD A,07FH
    IN A,(254) ; Reads 0x7FFE which is the bottom row of the keyboard
    AND 1
    JP NZ,LOOP ; Checks bit 0, which is the SPACE key
    LD BC,65533 ; AY OUTPUT PORTS (FFFD, BFFD)
    LD A,7
    OUT (C),A
    LD BC,49149
    LD A,63 ; Set AY register 7 to 63 - i.e. all channels OFF
    OUT (C),A

    POP HL
    POP DE
    POP BC
    POP AF
    RET

    I’m not going through the sub routines of the loop, other than to note the following:

    • UPDATE is a whole series of instructions that basically do the following to output the HEX value of a sound parameter:
    LD A, (contents of one of the sound variables)
    LD DE, (corresponding screen address for the variable to be displayed)
    CALL HEX
    • REFRESH runs the sound driver itself, as described in Z80 and AY-3-8910.
    • CLOCK decrements the FIFTY variable and every time it gets to zero updates SECS and MINS and writes them out to the display. As it also uses the HEX routine, I guess it is storing the time using binary-coded decimal (BCD).
    • KEYSCAN reads the last key pressed from the system variable location stored in ASCII (23560 / 0x5C08).

    At some point I might come back and work out what keys do what…

    Closing Thoughts

    I’d really like to get some of this code running on some of the alternate Z80 platforms I have. Getting the sound output shouldn’t be too much of an issue, but I’d really like to have some kind of display too.

    But as can be seen above, the tester UI is pretty well tied into the oddities of the ZX Spectrum display, so porting it won’t be trivial.

    I suspect there are already some existing AY/chiptune players that perhaps would be a better starting point, but from what I’ve seen they tend to stream the register data after having sampled it at regular intervals, which isn’t quite what I was after… there would be something really quite interesting about actually running Ste Ruddy’s Sound Driver with a Tim Follin soundtrack programmed in.

    Kevin

    #ay38910 #TimFollin #zxSpectrum
  18. Z80 and AY-3-8910 – Part 2

    I’ve spent a bit of time looking at the “Tester” part of the AY driver code for Tim Follin’s music archive that I talked about in Z80 and AY-3-8910.

    This is documenting what I think I’ve worked out so far for the tester code.

    The Sound Tester

    As previously mentioned, there are essentially three parts to the code in Follin archive:

    • The tune and effect data.
    • Ste Ruddy’s Sound Driver.
    • A tracker-style (ish) tester UI application.

    The first part looked at the sound driver itself, and essentially skipped over the tester part of the code. This post picks up on that tester code.

    Reminder, from part one, the main structure is as follows:

    Code_Start: EQU 40000
    Data_Start: EQU 50000

    ;-----------------------------
    ORG Code_Start

    ; The UI/tester code
    TESTER:
    LOOP: Calls the following for each scan:
    HALT - Suspends until an interrupt comes in?
    CALL UPDATE
    CALL REFRESH
    CALL CLOCK
    CALL KEYSCAN
    Repeat as necessary

    KEYSCAN: UI scanning
    CLOCK: Possibly maintain a 50Hz refresh rate clock?
    UPDATE: Loads the internal state of all sound variables from
    the driver and displays them in real time via the UI.

    ; The sound driver
    CODE_TOP:
    TUNE: Select which tune to play.
    TUNE_IN: Init all internal sound state variables for a new tune.
    TUNEOFF: Stop a playing tune, eg to change tune or start an FX.

    FX: Start playing an FX.
    FLOOP: Keep processing FX instructions until complete.

    REFRESH: "run" a scan of the sound driver updating and outputting the sound

    The Tester Code

    Initialisation information and main screen data:

    ;**************************************

    ; Z80 AY MUSIC DRIVER

    ;**************************************

    ; ORG 40000
    ; LOAD 0C000H

    ;======================================
    ;STACK DEPTHS

    SD: EQU 3

    ;======================================

    ASCII: EQU 23560 ; 23560 = $5C08 = System Variable "LAST K"

    TESTER: PUSH AF
    PUSH BC
    PUSH DE
    PUSH HL

    XOR A ; ASCII = MINS = SECS = 0
    LD (ASCII),A
    LD (MINS),A
    LD (SECS),A

    CALL TUNEOFF ; TUNE initialisation
    CALL STACKMESS ; Kick off the Tester code!

    DB CLS ; The start of the main UI data
    DB AT,0,0
    DB INK,01010111B
    DB "'AY' MUSIC DRIVE"
    DB "R V2 BY S.RUDDY"

    ... Skip ...

    DB INK,64+5
    DB "VOLUME "
    DB " "
    DB 255

    ... Skip ...

    AT: EQU 22
    INK: EQU 16
    CLS: EQU 15

    STACKMESS: POP IX
    CALL MESS
    JP (IX)

    There is a whole lot of screen data in DB blocks which includes some “op codes” that are defined later: AT, INK, CLS. These are special codes that are used by the ROM-based print routines (more here), as used by Sinclair BASIC, but in this case they are spelt out directly, later in code. The final 255 signifies the end of the screen data.

    So how are these definitions handled? That all comes up in the “MESS” routine I’ll get to in a moment, but first that “STACKMESS” routine needs a bit of explanation.

    When a CALL instruction happens, such as the CALL STACKMESS at the start, the current program counter gets pushed onto the stack. In this case the current PC will point to the instruction after the CALL, which happens to be the start of the screen data. So the POP IX will grab the address of the screen data and drop it into IX and then call the “MESS” function to actually get on with it!

    But before I get to that, there is some more code after the screen data:

                    LD HL,CALC1
    PUSH HL
    LD A,H
    LD DE,4067H ; Output high byte
    CALL HEX
    POP HL
    LD A,L
    LD DE,4069H ; Output low byte
    CALL HEX

    LD HL,(CALC2)
    PUSH HL
    LD A,H
    LD DE,4071H ; Output number of Tunes
    CALL HEX
    POP HL
    LD A,L
    LD DE,4073H ; Output number of effects
    CALL HEX

    LD HL,CALC1
    LD DE,(CALC2)
    ADD HL,DE
    PUSH HL
    LD A,H
    LD DE,407CH ; Not entirely sure what this is outputting...
    CALL HEX
    POP HL
    LD A,L
    LD DE,407EH
    CALL HEX

    This is writing some basic data out to the display. CALC1 seems to relate to code section size. I believe CALC2 is the start address of the tune data, which is the following:

                    ORG Data_Start

    TUNES: EQU 5
    EFFECTS: EQU 21

    All three of these sections are outputting a 16-bit value in two single-byte chunks using the “HEX” routine, which takes a screen address (in the range $4000-$57FF) and outputs a hex number at that screen location.

    So while I’m at it then, how is that HEX function working?

    ;--------------------------------------
    HEX: INC DE ; DE contains the screen address to use
    PUSH AF ; Start with DE+1
    CALL ONEnib ; Write out the LOW 4-bits
    POP AF
    RRA ; A = A>>4
    RRA ; to write out HIGH 4-bits
    RRA
    RRA
    DEC DE ; Back to original DE screen address
    ONEnib: AND 15 ; A = A & 0xF
    ADD A ; BC = A * 2
    LD C,A
    LD B,0
    LD HL,ROM_TAB ; Read from ROM_TAB[BC]
    ADD HL,BC
    LD A,(HL)
    INC HL
    LD H,(HL)
    LD L,A ; HL = (uint16_t)ROM_TAB[A]
    MIKESbug: LD C,D ; So HL now points to character bitmap in ROM
    LD B,8 ; Write out 8 bytes to display memory directly
    PRloop: LD A,(HL) ; (DE) = (HL)
    LD (DE),A
    INC HL ; HL++
    INC D ; NB: Layout of display mem means D++ is next line of char
    ; for same value of E.
    DJNZ PRloop ; WHILE (B-- > 0)
    LD D,C ; (Restore D before returning, so DE still = screen addr)
    RET

    ROM_TAB: DW 3D80H ; ROM character set: 3D80 = "0"
    DW 3D88H ; Each char = 8 x 8 bits
    DW 3D90H
    DW 3D98H
    DW 3DA0H
    DW 3DA8H
    DW 3DB0H
    DW 3DB8H
    DW 3DC0H
    DW 3DC8H ; = "9"
    DW 3E08H ; = "A"
    DW 3E10H
    DW 3E18H
    DW 3E20H
    DW 3E28H
    DW 3E30H ; = "F"

    This is making use of the character set stored in the Spectrum ROM (more here) which is indexed via a 16-word jump table mapping the characters onto each of the 16 hex characters: 0..9, A..F.

    Then each byte, 8 in total, of the character is written directly out to the Spectrum screen memory taking advantage of the odd formatting of the screen memory to easily skip to the next line of the display for each line of the character (more here).

    So before I get into the main update loop, how the screen initialised and set up? That happens in the “MESS” and some ancillary functions.

    MESS:           LD A,(IX+0)         ; At this point, McursorX, McursorY = (0,0)
    INC IX ; So read a byte of screen data
    OR A
    RET M ; Stop IF A=255 (i.e. negative)
    CP 32
    JR C,Mcontrol ; IF A<32 process control character then RET back to "MESS"
    CALL Mgetchar ; ELSE Process character
    CALL Mgetaddr ; Get screen address for next output in DE
    CALL MIKESbug ; Output the character
    CALL PRattr ; Set the colour attributes
    CALL INCcursor ; Update the screen position for the next byte of screen data
    JR MESS

    Mcontrol: LD HL,MESS ; Stick the address of "MESS" on the stack for the RET
    PUSH HL
    CP 15 ; IF A == CLS
    JR Z,Mcls
    CP 22 ; IF A == AT
    JP Z,Mat
    CP 16 ; IF A == INK
    JR Z,Mink
    RET ; RETurn to "MESS"

    Mcolour: DB 0 ; Working variables for cursor position and colour
    McursorX: DB 0
    McursorY: DB 0 ; Has to be directly after McursorX (see later)

    Mink: LD A,(IX+0) ; Process INK to set colour
    INC IX
    LD (Mcolour),A
    RET

    Mcls: LD HL,4000H ; Process CLS to clear screen
    LD (HL),L
    LD DE,4001H
    LD BC,1AFFH
    LDIR
    LD (McursorX),BC
    RET

    INCcursor: LD HL,McursorX ; Moves the cursor on one position
    LD A,(HL)
    INC A
    AND 31
    LD (HL),A ; X++; X = X % 32
    RET NZ ; IF X==0; Y++
    INC HL ; Assumes McursorY is McursorX++
    INC (HL)
    RET

    Mgetchar: LD L,A ; HL = A*8 + 3C00
    LD H,0 ; Note: A > 32; where 32="Space"
    ADD HL,HL ; In ROM, space is address 3D00
    ADD HL,HL ; 32 * 8 = 0x100
    ADD HL,HL
    LD BC,3C00H
    ADD HL,BC ; HL = Start address of character map for char in A in ROM
    RET

    .... skip ....

    Mgetaddr: LD A,(McursorY) ; Calculate the screen address for (McursorX, McursorY)
    AND 18H
    OR 40H
    LD D,A
    LD A,(McursorY)
    RRCA
    RRCA
    RRCA
    AND 0E0H
    LD E,A
    LD A,(McursorX)
    ADD E
    LD E,A
    RET ; DE = required screen address

    Mat: LD A,(IX+0) ; Set cursor to provided X, Y in screen data
    LD (McursorX),A
    INC IX
    LD A,(IX+0)
    LD (McursorY),A
    INC IX
    RET

    PRattr: LD A,D ; Get address of ATTRibute memory
    RRA
    RRA
    RRA
    AND 3
    OR 58H
    LD D,A
    LD A,(Mcolour)
    LD (DE),A ; And set the colour
    RET

    Basically this loop keeps working on the provided screen data until the value 255 is found, at which point it returns. There are two paths for handling the data:

    • IF the value is < 32 then it is a control value. Only CLS, AT and INK are recognised.
    • ELSE the value is assumed to be an ASCII character and is displayed.

    Whatever is happening, happens at the coordinates given by (McursorX, McursorY) which start out as (0,0) and get updated automatically when a character is output, or in response to an AT command. INK will set the required colour in Mcolour, which again starts out as 0. This is applied after the character is written to the screen, using the PRattr function.

    There is a fun bit of optimisation going on in Mcontrol. At the start it pushes the address of the MESS function on the stack, which means that the RET will jump back to the start of MESS rather than where the jump happened to Mcontrol itself.

    There is another shortcut in the Mcls function: LDIR. From http://z80-heaven.wikidot.com/instructions-set:ldir: “Repeats LDI (LD (DE),(HL), then increments DE, HL, and decrements BC) until BC=0.” By setting the contents of HL (the first byte of the display) to zero, this will tile that same value across the display memory until BC, which starts at $1AFF, is zero. This will zero the whole display – both pixels and attributes – from 0x4000 through to 0x5AFF.

    Now finally, we get to the main update loop.

    LOOP:           
    HALT
    CALL UPDATE ; Update the display from the current Sound parameters
    LD A,2
    OUT (254),A ; Set border to 2
    CALL REFRESH ; Update the sound driver parameters
    XOR A
    OUT (254),A ; Set border to 0
    CALL CLOCK ; Run 50Hz clock
    CALL KEYSCAN ; Guess what - scans the keyboard 🙂
    LD A,07FH
    IN A,(254) ; Reads 0x7FFE which is the bottom row of the keyboard
    AND 1
    JP NZ,LOOP ; Checks bit 0, which is the SPACE key
    LD BC,65533 ; AY OUTPUT PORTS (FFFD, BFFD)
    LD A,7
    OUT (C),A
    LD BC,49149
    LD A,63 ; Set AY register 7 to 63 - i.e. all channels OFF
    OUT (C),A

    POP HL
    POP DE
    POP BC
    POP AF
    RET

    I’m not going through the sub routines of the loop, other than to note the following:

    • UPDATE is a whole series of instructions that basically do the following to output the HEX value of a sound parameter:
    LD A, (contents of one of the sound variables)
    LD DE, (corresponding screen address for the variable to be displayed)
    CALL HEX
    • REFRESH runs the sound driver itself, as described in Z80 and AY-3-8910.
    • CLOCK decrements the FIFTY variable and every time it gets to zero updates SECS and MINS and writes them out to the display. As it also uses the HEX routine, I guess it is storing the time using binary-coded decimal (BCD).
    • KEYSCAN reads the last key pressed from the system variable location stored in ASCII (23560 / 0x5C08).

    At some point I might come back and work out what keys do what…

    Closing Thoughts

    I’d really like to get some of this code running on some of the alternate Z80 platforms I have. Getting the sound output shouldn’t be too much of an issue, but I’d really like to have some kind of display too.

    But as can be seen above, the tester UI is pretty well tied into the oddities of the ZX Spectrum display, so porting it won’t be trivial.

    I suspect there are already some existing AY/chiptune players that perhaps would be a better starting point, but from what I’ve seen they tend to stream the register data after having sampled it at regular intervals, which isn’t quite what I was after… there would be something really quite interesting about actually running Ste Ruddy’s Sound Driver with a Tim Follin soundtrack programmed in.

    Kevin

    #ay38910 #TimFollin #zxSpectrum
  19. Z80 and AY-3-8910 – Part 2

    I’ve spent a bit of time looking at the “Tester” part of the AY driver code for Tim Follin’s music archive that I talked about in Z80 and AY-3-8910.

    This is documenting what I think I’ve worked out so far for the tester code.

    The Sound Tester

    As previously mentioned, there are essentially three parts to the code in Follin archive:

    • The tune and effect data.
    • Ste Ruddy’s Sound Driver.
    • A tracker-style (ish) tester UI application.

    The first part looked at the sound driver itself, and essentially skipped over the tester part of the code. This post picks up on that tester code.

    Reminder, from part one, the main structure is as follows:

    Code_Start: EQU 40000
    Data_Start: EQU 50000

    ;-----------------------------
    ORG Code_Start

    ; The UI/tester code
    TESTER:
    LOOP: Calls the following for each scan:
    HALT - Suspends until an interrupt comes in?
    CALL UPDATE
    CALL REFRESH
    CALL CLOCK
    CALL KEYSCAN
    Repeat as necessary

    KEYSCAN: UI scanning
    CLOCK: Possibly maintain a 50Hz refresh rate clock?
    UPDATE: Loads the internal state of all sound variables from
    the driver and displays them in real time via the UI.

    ; The sound driver
    CODE_TOP:
    TUNE: Select which tune to play.
    TUNE_IN: Init all internal sound state variables for a new tune.
    TUNEOFF: Stop a playing tune, eg to change tune or start an FX.

    FX: Start playing an FX.
    FLOOP: Keep processing FX instructions until complete.

    REFRESH: "run" a scan of the sound driver updating and outputting the sound

    The Tester Code

    Initialisation information and main screen data:

    ;**************************************

    ; Z80 AY MUSIC DRIVER

    ;**************************************

    ; ORG 40000
    ; LOAD 0C000H

    ;======================================
    ;STACK DEPTHS

    SD: EQU 3

    ;======================================

    ASCII: EQU 23560 ; 23560 = $5C08 = System Variable "LAST K"

    TESTER: PUSH AF
    PUSH BC
    PUSH DE
    PUSH HL

    XOR A ; ASCII = MINS = SECS = 0
    LD (ASCII),A
    LD (MINS),A
    LD (SECS),A

    CALL TUNEOFF ; TUNE initialisation
    CALL STACKMESS ; Kick off the Tester code!

    DB CLS ; The start of the main UI data
    DB AT,0,0
    DB INK,01010111B
    DB "'AY' MUSIC DRIVE"
    DB "R V2 BY S.RUDDY"

    ... Skip ...

    DB INK,64+5
    DB "VOLUME "
    DB " "
    DB 255

    ... Skip ...

    AT: EQU 22
    INK: EQU 16
    CLS: EQU 15

    STACKMESS: POP IX
    CALL MESS
    JP (IX)

    There is a whole lot of screen data in DB blocks which includes some “op codes” that are defined later: AT, INK, CLS. These are special codes that are used by the ROM-based print routines (more here), as used by Sinclair BASIC, but in this case they are spelt out directly, later in code. The final 255 signifies the end of the screen data.

    So how are these definitions handled? That all comes up in the “MESS” routine I’ll get to in a moment, but first that “STACKMESS” routine needs a bit of explanation.

    When a CALL instruction happens, such as the CALL STACKMESS at the start, the current program counter gets pushed onto the stack. In this case the current PC will point to the instruction after the CALL, which happens to be the start of the screen data. So the POP IX will grab the address of the screen data and drop it into IX and then call the “MESS” function to actually get on with it!

    But before I get to that, there is some more code after the screen data:

                    LD HL,CALC1
    PUSH HL
    LD A,H
    LD DE,4067H ; Output high byte
    CALL HEX
    POP HL
    LD A,L
    LD DE,4069H ; Output low byte
    CALL HEX

    LD HL,(CALC2)
    PUSH HL
    LD A,H
    LD DE,4071H ; Output number of Tunes
    CALL HEX
    POP HL
    LD A,L
    LD DE,4073H ; Output number of effects
    CALL HEX

    LD HL,CALC1
    LD DE,(CALC2)
    ADD HL,DE
    PUSH HL
    LD A,H
    LD DE,407CH ; Not entirely sure what this is outputting...
    CALL HEX
    POP HL
    LD A,L
    LD DE,407EH
    CALL HEX

    This is writing some basic data out to the display. CALC1 seems to relate to code section size. I believe CALC2 is the start address of the tune data, which is the following:

                    ORG Data_Start

    TUNES: EQU 5
    EFFECTS: EQU 21

    All three of these sections are outputting a 16-bit value in two single-byte chunks using the “HEX” routine, which takes a screen address (in the range $4000-$57FF) and outputs a hex number at that screen location.

    So while I’m at it then, how is that HEX function working?

    ;--------------------------------------
    HEX: INC DE ; DE contains the screen address to use
    PUSH AF ; Start with DE+1
    CALL ONEnib ; Write out the LOW 4-bits
    POP AF
    RRA ; A = A>>4
    RRA ; to write out HIGH 4-bits
    RRA
    RRA
    DEC DE ; Back to original DE screen address
    ONEnib: AND 15 ; A = A & 0xF
    ADD A ; BC = A * 2
    LD C,A
    LD B,0
    LD HL,ROM_TAB ; Read from ROM_TAB[BC]
    ADD HL,BC
    LD A,(HL)
    INC HL
    LD H,(HL)
    LD L,A ; HL = (uint16_t)ROM_TAB[A]
    MIKESbug: LD C,D ; So HL now points to character bitmap in ROM
    LD B,8 ; Write out 8 bytes to display memory directly
    PRloop: LD A,(HL) ; (DE) = (HL)
    LD (DE),A
    INC HL ; HL++
    INC D ; NB: Layout of display mem means D++ is next line of char
    ; for same value of E.
    DJNZ PRloop ; WHILE (B-- > 0)
    LD D,C ; (Restore D before returning, so DE still = screen addr)
    RET

    ROM_TAB: DW 3D80H ; ROM character set: 3D80 = "0"
    DW 3D88H ; Each char = 8 x 8 bits
    DW 3D90H
    DW 3D98H
    DW 3DA0H
    DW 3DA8H
    DW 3DB0H
    DW 3DB8H
    DW 3DC0H
    DW 3DC8H ; = "9"
    DW 3E08H ; = "A"
    DW 3E10H
    DW 3E18H
    DW 3E20H
    DW 3E28H
    DW 3E30H ; = "F"

    This is making use of the character set stored in the Spectrum ROM (more here) which is indexed via a 16-word jump table mapping the characters onto each of the 16 hex characters: 0..9, A..F.

    Then each byte, 8 in total, of the character is written directly out to the Spectrum screen memory taking advantage of the odd formatting of the screen memory to easily skip to the next line of the display for each line of the character (more here).

    So before I get into the main update loop, how the screen initialised and set up? That happens in the “MESS” and some ancillary functions.

    MESS:           LD A,(IX+0)         ; At this point, McursorX, McursorY = (0,0)
    INC IX ; So read a byte of screen data
    OR A
    RET M ; Stop IF A=255 (i.e. negative)
    CP 32
    JR C,Mcontrol ; IF A<32 process control character then RET back to "MESS"
    CALL Mgetchar ; ELSE Process character
    CALL Mgetaddr ; Get screen address for next output in DE
    CALL MIKESbug ; Output the character
    CALL PRattr ; Set the colour attributes
    CALL INCcursor ; Update the screen position for the next byte of screen data
    JR MESS

    Mcontrol: LD HL,MESS ; Stick the address of "MESS" on the stack for the RET
    PUSH HL
    CP 15 ; IF A == CLS
    JR Z,Mcls
    CP 22 ; IF A == AT
    JP Z,Mat
    CP 16 ; IF A == INK
    JR Z,Mink
    RET ; RETurn to "MESS"

    Mcolour: DB 0 ; Working variables for cursor position and colour
    McursorX: DB 0
    McursorY: DB 0 ; Has to be directly after McursorX (see later)

    Mink: LD A,(IX+0) ; Process INK to set colour
    INC IX
    LD (Mcolour),A
    RET

    Mcls: LD HL,4000H ; Process CLS to clear screen
    LD (HL),L
    LD DE,4001H
    LD BC,1AFFH
    LDIR
    LD (McursorX),BC
    RET

    INCcursor: LD HL,McursorX ; Moves the cursor on one position
    LD A,(HL)
    INC A
    AND 31
    LD (HL),A ; X++; X = X % 32
    RET NZ ; IF X==0; Y++
    INC HL ; Assumes McursorY is McursorX++
    INC (HL)
    RET

    Mgetchar: LD L,A ; HL = A*8 + 3C00
    LD H,0 ; Note: A > 32; where 32="Space"
    ADD HL,HL ; In ROM, space is address 3D00
    ADD HL,HL ; 32 * 8 = 0x100
    ADD HL,HL
    LD BC,3C00H
    ADD HL,BC ; HL = Start address of character map for char in A in ROM
    RET

    .... skip ....

    Mgetaddr: LD A,(McursorY) ; Calculate the screen address for (McursorX, McursorY)
    AND 18H
    OR 40H
    LD D,A
    LD A,(McursorY)
    RRCA
    RRCA
    RRCA
    AND 0E0H
    LD E,A
    LD A,(McursorX)
    ADD E
    LD E,A
    RET ; DE = required screen address

    Mat: LD A,(IX+0) ; Set cursor to provided X, Y in screen data
    LD (McursorX),A
    INC IX
    LD A,(IX+0)
    LD (McursorY),A
    INC IX
    RET

    PRattr: LD A,D ; Get address of ATTRibute memory
    RRA
    RRA
    RRA
    AND 3
    OR 58H
    LD D,A
    LD A,(Mcolour)
    LD (DE),A ; And set the colour
    RET

    Basically this loop keeps working on the provided screen data until the value 255 is found, at which point it returns. There are two paths for handling the data:

    • IF the value is < 32 then it is a control value. Only CLS, AT and INK are recognised.
    • ELSE the value is assumed to be an ASCII character and is displayed.

    Whatever is happening, happens at the coordinates given by (McursorX, McursorY) which start out as (0,0) and get updated automatically when a character is output, or in response to an AT command. INK will set the required colour in Mcolour, which again starts out as 0. This is applied after the character is written to the screen, using the PRattr function.

    There is a fun bit of optimisation going on in Mcontrol. At the start it pushes the address of the MESS function on the stack, which means that the RET will jump back to the start of MESS rather than where the jump happened to Mcontrol itself.

    There is another shortcut in the Mcls function: LDIR. From http://z80-heaven.wikidot.com/instructions-set:ldir: “Repeats LDI (LD (DE),(HL), then increments DE, HL, and decrements BC) until BC=0.” By setting the contents of HL (the first byte of the display) to zero, this will tile that same value across the display memory until BC, which starts at $1AFF, is zero. This will zero the whole display – both pixels and attributes – from 0x4000 through to 0x5AFF.

    Now finally, we get to the main update loop.

    LOOP:           
    HALT
    CALL UPDATE ; Update the display from the current Sound parameters
    LD A,2
    OUT (254),A ; Set border to 2
    CALL REFRESH ; Update the sound driver parameters
    XOR A
    OUT (254),A ; Set border to 0
    CALL CLOCK ; Run 50Hz clock
    CALL KEYSCAN ; Guess what - scans the keyboard 🙂
    LD A,07FH
    IN A,(254) ; Reads 0x7FFE which is the bottom row of the keyboard
    AND 1
    JP NZ,LOOP ; Checks bit 0, which is the SPACE key
    LD BC,65533 ; AY OUTPUT PORTS (FFFD, BFFD)
    LD A,7
    OUT (C),A
    LD BC,49149
    LD A,63 ; Set AY register 7 to 63 - i.e. all channels OFF
    OUT (C),A

    POP HL
    POP DE
    POP BC
    POP AF
    RET

    I’m not going through the sub routines of the loop, other than to note the following:

    • UPDATE is a whole series of instructions that basically do the following to output the HEX value of a sound parameter:
    LD A, (contents of one of the sound variables)
    LD DE, (corresponding screen address for the variable to be displayed)
    CALL HEX
    • REFRESH runs the sound driver itself, as described in Z80 and AY-3-8910.
    • CLOCK decrements the FIFTY variable and every time it gets to zero updates SECS and MINS and writes them out to the display. As it also uses the HEX routine, I guess it is storing the time using binary-coded decimal (BCD).
    • KEYSCAN reads the last key pressed from the system variable location stored in ASCII (23560 / 0x5C08).

    At some point I might come back and work out what keys do what…

    Closing Thoughts

    I’d really like to get some of this code running on some of the alternate Z80 platforms I have. Getting the sound output shouldn’t be too much of an issue, but I’d really like to have some kind of display too.

    But as can be seen above, the tester UI is pretty well tied into the oddities of the ZX Spectrum display, so porting it won’t be trivial.

    I suspect there are already some existing AY/chiptune players that perhaps would be a better starting point, but from what I’ve seen they tend to stream the register data after having sampled it at regular intervals, which isn’t quite what I was after… there would be something really quite interesting about actually running Ste Ruddy’s Sound Driver with a Tim Follin soundtrack programmed in.

    Kevin

    #ay38910 #TimFollin #zxSpectrum
  20. Mini-Compendium: Power, Safety, Authority Gradients, and the Power of Elites

    Here’s some articles, mostly full-text links, exploring power within organisations.

    Includes broader social power, power gradients, voice, and more.

    Feel free to shout me a coffee if you’d like to support the growth of my site:

    https://buymeacoffee.com/benhutchinson

    Full-Text Articles

    [Below link will say ‘Discursive effects of safety science’. Download it and its a whole book with the above chapter]

    https://www.researchgate.net/profile/Johan-Bergstroem/publication/335162893_The_Discursive_Effects_of_Safety_Science/links/650ad3d6d5293c106cca099b/The-Discursive-Effects-of-Safety-Science.pdf#page=124

    https://sidneydekker.com/wp-content/uploads/2024/12/SafetyInPower.pdf

    https://sidneydekker.com/wp-content/uploads/2024/12/JustCultureCritique.pdf

    https://d1wqtxts1xzle7.cloudfront.net/79944444/1d996e_7f6d510450714d16a785e27021ff18b8-libre.pdf?1643583068=&response-content-disposition=inline%3B+filename%3DLeader_Humility_and_Team_Creativity_The.pdf&Expires=1742163884&Signature=dpjnEIAR6EST6HE0kx1~oMIMWZT7p~7tI4qslcYJO9tzlH5l8JsrCpijy4umQXbVzcBvJB799-d~rhpyacjjc0xF-SL0elgOB3llLFvyoWfjBzmEyjKVv8-nmFZNgByEjk9ymu5mzK5W5a9puCm5YBcOolRSmHzoHIlDDNEBxCr-sVGZddRRRxYtYKl83Qau5zlPOJq9nWSe7EIUZcB9-YD6i8jtSwXF5DiStJgRZRvR7ydIWxhKoZwCUe4qUPBAPYZvv3ybYIuARgj7KlEJV8mAPUw3MZSpROLY8YP~m52Yw6lJ8iCZMx2up2xyEi-gyoa2geJjmDaTB6Ic~BbX2g__&Key-Pair-Id=APKAJLOHF5GGSLRBV4ZA

    https://doi.org/10.1016/j.ssci.2024.106446

    https://pmc.ncbi.nlm.nih.gov/articles/PMC4880472/pdf/nihms5702.pdf

    https://www.researchgate.net/profile/Wai-Yoong/publication/362609810_Understanding_authority_gradient_tips_for_speaking_up_for_patient_safety_and_how_to_enhance_the_listening_response/links/67a268e296e7fb48b9b46fa6/Understanding-authority-gradient-tips-for-speaking-up-for-patient-safety-and-how-to-enhance-the-listening-response.pdf

    https://www.researchgate.net/profile/Erin-Stevens-2/publication/350469124_The_impact_of_power_on_health_care_team_performance_and_patient_safety_A_review_of_the_literature/links/608758b98ea909241e28c310/The-impact-of-power-on-health-care-team-performance-and-patient-safety-A-review-of-the-literature.pdf

    https://onlinelibrary.wiley.com/doi/pdf/10.1197/j.aem.2004.07.005

    https://eprints.lse.ac.uk/90953/1/Tear_Safety-culture-and-power.pdf

    https://ecampus.nmit.ac.nz/moodle/pluginfile.php/2178236/mod_resource/content/1/Trust%2C%20Power%20and%20safety%20in%20the%20social%20work%20supervisory%20relationship%20%282017%29.pdf

    https://research-repository.griffith.edu.au/server/api/core/bitstreams/6be4c986-c4d5-5145-9360-6ceb388de953/content

    https://sidneydekker.stackedsite.com/wp-content/uploads/sites/899/2017/09/ZeroVision.pdf

    https://www.academia.edu/download/86424812/j.ssci.2019.09.02820220524-1-1nt6327.pdf

    https://doi.org/10.1016/j.ssci.2018.10.025

    https://journals.sagepub.com/doi/pdf/10.1177/2327857921101130

    https://journals.sagepub.com/doi/pdf/10.1177/25160435211027035?fbclid=IwAR21-3M4frgjnjiiesS5EZCfvfnISjdz7M7P8E130r2NLIPcUrqflEellLk&

    https://doi.org/10.1016/j.ssci.2019.04.039

    https://www.tandfonline.com/doi/pdf/10.1080/09585192.2024.2342294

    https://digitalcommons.osgoode.yorku.ca/cgi/viewcontent.cgi?article=1001&context=ohlj

    https://eprints.lse.ac.uk/109877/1/Noort_et_al._MANUSCRIPT_for_LSE_online.pdf

    https://doi.org/10.1016/j.ssci.2020.105120

    https://www.ida.liu.se/~769A22/Seminarier/articles/safety_counterculture.pdf

    https://doi.org/10.3389/fpsyg.2019.00668

    https://research.vu.nl/ws/portalfiles/portal/2277897/202659.pdf

    https://journals.sagepub.com/doi/pdf/10.1177/0096340211426395

    https://www.researchgate.net/profile/Andrew-Hopkins-4/publication/279759571_The_Limits_of_Normal_Accident_Theory/links/590ef803a6fdccad7b123cb3/The-Limits-of-Normal-Accident-Theory.pdf

    https://www.academia.edu/download/107807207/soc4.1273720231125-1-c3885x.pdf

    https://www.tandfonline.com/doi/pdf/10.1080/1463922X.2021.1881653

    https://www.researchgate.net/profile/Susan-Silbey/publication/228173756_Taming_Prometheus_Talk_About_Safety_and_Culture/links/55103d080cf203521969d837/Taming-Prometheus-Talk-About-Safety-and-Culture.pdf

    https://safety177496371.wordpress.com/2022/02/08/ruthless-exploiters-or-ethical-guardians-of-the-workforce-powerful-ceos-and-their-impact-on-workplace-safety-and-health/

    https://safety177496371.wordpress.com/2025/01/23/safety-culture-and-power-dynamics-in-organizations/

    https://www.researchgate.net/profile/Erin-Stevens-2/publication/350469124_The_impact_of_power_on_health_care_team_performance_and_patient_safety_A_review_of_the_literature/links/608758b98ea909241e28c310/The-impact-of-power-on-health-care-team-performance-and-patient-safety-A-review-of-the-literature.pdf

    https://www.academia.edu/download/110471105/JHQ.000000000000025720240115-1-n29aqn.pdf

    https://www.scielo.br/j/rbso/a/ghnrhMFyqSssFxFFSMfQbXd/?format=pdf&lang=en

    https://dialnet.unirioja.es/descarga/articulo/9554587.pdf

    https://ap-st01.ext.exlibrisgroup.com/61SCU_INST/upload/1741316102864/The%20construction%20and%20legitimation%20of%20workplace%20bullying%20in%20the%20pu.pdf?Expires=1741316223&Signature=itZRT0uJOuRdUpI5C3P6RhfqsmZwlNkxQpZQVbs-OlGf4~VM9H7Hsog9a5Nd3X9WWTDqhARrGVNkArCuMcFeuEg38qP5zQdJzx~V7ldivDFG1IBjRzhKkDD1qPB5-0TSTODiNLdesbPVP6ya-inEspaJZVJuekE6WH5lf-TnDICzt5NS-eMYWxjZBtul1KYSdSNXh55As8qvaHpcDQVZzmUTGO9FJgFjtAJiKL~pyn7E~z5Cj13j-of5IfY~jLA6KNFZ-wrB9YBMLEHzqcsAIudz8QUICkkQYYvG4H8MFEESfS~ShEhvYowHBLg6fS0NzNTOzZBmQ4Ii3JWeoys5OQ__&Key-Pair-Id=APKAJ72OZCZ36VGVASIA

    https://www.academia.edu/download/49166705/j.socscimed.2009.09.05220160927-27290-19a6oxp.pdf

    https://www.academia.edu/download/30990385/2010_Clinical_supervision_Hdez_McDowell.pdf

    https://studystock.wordpress.com/wp-content/uploads/2013/11/understanding-power-in-organizations.pdf

    https://openaccess.city.ac.uk/id/eprint/8236/4/Annals%20accepted.pdf

    https://www.academia.edu/download/89536105/0003-066x.45.2.17920220812-1-11im1f6.pdf

    http://www.contrib.andrew.cmu.edu/~krack/documents/pubs/1990/1990%20Assessing%20the%20Political%20Landscape.pdf

    https://www.academia.edu/download/31144526/administrative_science_quarterly_7_1972_mechanic.pdf

    https://journals.sagepub.com/doi/pdf/10.1177/26317877221084714

    https://ascelibrary.org/doi/pdf/10.1061/%28ASCE%29LM.1943-5630.0000018?download=true

    https://www.researchgate.net/profile/Sean-Buchanan/publication/327477734_Power_Institutions_and_Organizations/links/64888219d702370600ef726d/Power-Institutions-and-Organizations.pdf

    https://www.researchgate.net/profile/Belle-Ragins/publication/232499085_Gender_and_Power_in_Organizations_A_Longitudinal_Perspective/links/56baaf1f08ae3af6847d8c13/Gender-and-Power-in-Organizations-A-Longitudinal-Perspective.pdf

    https://www.researchgate.net/profile/Stewart-Ranson/publication/247733580_Power_and_Advantage_in_Organizations/links/0deec53c68032b4ade000000/Power-and-Advantage-in-Organizations.pdf

    https://citeseerx.ist.psu.edu/document?repid=rep1&type=pdf&doi=c72a7081f0f19c3f3b4e99c492f16ac2f8a21c92

    https://citeseerx.ist.psu.edu/document?repid=rep1&type=pdf&doi=902977fcabe0928dc829ca14ef62a8b26e5b8dad

    https://www.jaapboonstra.nl/wp-content/uploads/2013/01/Power-dynamics-and-organizational-change2.pdf

    https://www.researchgate.net/profile/Jori-Kalkman/publication/308898552_Inter-Organizational_Disaster_Management_Projects_Finding_the_Middle_Way_between_Trust_and_Control/links/5c5a953692851c48a9bd7ccc/Inter-Organizational-Disaster-Management-Projects-Finding-the-Middle-Way-between-Trust-and-Control.pdf

    https://www.humanfactors.lth.se/fileadmin/lusa/Sidney_Dekker/articles/2003_and_before/SuparamaniamDekker2003.pdf

    https://mutualaiddisasterrelief.org/wp-content/uploads/2024/05/The_Biopolitics_of_Disaster_Power_Discourses_and_Practices.pdf

    https://www.diva-portal.org/smash/get/diva2:513208/FULLTEXT01.pdf

    https://onlinelibrary.wiley.com/doi/pdf/10.1002/rhc3.12218

    https://www.researchgate.net/profile/Howard-Schwartz-2/publication/40955166_On_the_psychodynamics_of_organizational_disaster_The_case_of_the_space_shuttle_Challenger/links/5cd08c0a92851c4eab87d179/On-the-psychodynamics-of-organizational-disaster-The-case-of-the-space-shuttle-Challenger.pdf

    https://doi.org/10.1016/j.ssci.2024.106446

    https://link.springer.com/content/pdf/10.1007/s10111-019-00545-8.pdf

    https://www.researchgate.net/profile/Emil-Kotsev/publication/381496413_Managing_the_Distance_with_the_Superior_Toward_a_Resolution_of_a_Subordinate_Manager’s_Dilemma/links/667a797b1dec0c3c6fa322e1/Managing-the-Distance-with-the-Superior-Toward-a-Resolution-of-a-Subordinate-Managers-Dilemma.pdf

    https://www.academia.edu/105928772/Danger_zone_Men_masculinity_and_occupational_health_and_safety_in_high_risk_occupations

    https://scholarlypublications.universiteitleiden.nl/access/item%3A3250217/view

    https://www.ida.liu.se/~769A22/Seminarier/articles/safety_counterculture.pdf

    https://doi.org/10.1016/j.ssci.2020.105120

    https://www.academia.edu/91832217/Power_organization_design_and_managerial_behaviour

    https://journal.psych.ac.cn/acps/EN/Y2022/V54/I5/549

    Abstracts & Extracts

    https://doi.org/10.1016/j.ssci.2008.02.004

    https://asmepublications.onlinelibrary.wiley.com/doi/abs/10.1111/medu.12947

    https://doi.org/10.1016/j.ssci.2013.10.013

    https://doi.org/10.1111/1468-5973.00032

    https://press.princeton.edu/books/paperback/9780691004129/normal-accidents?srsltid=AfmBOorMEgPZMJ-EM2pIOy_Mz1WhKd8IC6z_NGRBcycAgOP7Ktza7r5v

    https://press.uchicago.edu/ucp/books/book/chicago/M/bo3645893.html]

    LinkedIn post: https://www.linkedin.com/pulse/mini-compendium-power-safety-authority-gradients-ben-hutchinson-vttnc

    #accident #authorityGradient #downwardVoice #elites #politics #power #powerGradient #psychologicalSafety #safety #safetyScience #speakingUpToPower #voice

  21. Mini-Compendium: Power, Safety, Authority Gradients, and the Power of Elites

    Here’s some articles, mostly full-text links, exploring power within organisations.

    Includes broader social power, power gradients, voice, and more.

    Feel free to shout me a coffee if you’d like to support the growth of my site:

    https://buymeacoffee.com/benhutchinson

    Full-Text Articles

    [Below link will say ‘Discursive effects of safety science’. Download it and its a whole book with the above chapter]

    https://www.researchgate.net/profile/Johan-Bergstroem/publication/335162893_The_Discursive_Effects_of_Safety_Science/links/650ad3d6d5293c106cca099b/The-Discursive-Effects-of-Safety-Science.pdf#page=124

    https://sidneydekker.com/wp-content/uploads/2024/12/SafetyInPower.pdf

    https://sidneydekker.com/wp-content/uploads/2024/12/JustCultureCritique.pdf

    https://d1wqtxts1xzle7.cloudfront.net/79944444/1d996e_7f6d510450714d16a785e27021ff18b8-libre.pdf?1643583068=&response-content-disposition=inline%3B+filename%3DLeader_Humility_and_Team_Creativity_The.pdf&Expires=1742163884&Signature=dpjnEIAR6EST6HE0kx1~oMIMWZT7p~7tI4qslcYJO9tzlH5l8JsrCpijy4umQXbVzcBvJB799-d~rhpyacjjc0xF-SL0elgOB3llLFvyoWfjBzmEyjKVv8-nmFZNgByEjk9ymu5mzK5W5a9puCm5YBcOolRSmHzoHIlDDNEBxCr-sVGZddRRRxYtYKl83Qau5zlPOJq9nWSe7EIUZcB9-YD6i8jtSwXF5DiStJgRZRvR7ydIWxhKoZwCUe4qUPBAPYZvv3ybYIuARgj7KlEJV8mAPUw3MZSpROLY8YP~m52Yw6lJ8iCZMx2up2xyEi-gyoa2geJjmDaTB6Ic~BbX2g__&Key-Pair-Id=APKAJLOHF5GGSLRBV4ZA

    https://doi.org/10.1016/j.ssci.2024.106446

    https://pmc.ncbi.nlm.nih.gov/articles/PMC4880472/pdf/nihms5702.pdf

    https://www.researchgate.net/profile/Wai-Yoong/publication/362609810_Understanding_authority_gradient_tips_for_speaking_up_for_patient_safety_and_how_to_enhance_the_listening_response/links/67a268e296e7fb48b9b46fa6/Understanding-authority-gradient-tips-for-speaking-up-for-patient-safety-and-how-to-enhance-the-listening-response.pdf

    https://www.researchgate.net/profile/Erin-Stevens-2/publication/350469124_The_impact_of_power_on_health_care_team_performance_and_patient_safety_A_review_of_the_literature/links/608758b98ea909241e28c310/The-impact-of-power-on-health-care-team-performance-and-patient-safety-A-review-of-the-literature.pdf

    https://onlinelibrary.wiley.com/doi/pdf/10.1197/j.aem.2004.07.005

    https://eprints.lse.ac.uk/90953/1/Tear_Safety-culture-and-power.pdf

    https://ecampus.nmit.ac.nz/moodle/pluginfile.php/2178236/mod_resource/content/1/Trust%2C%20Power%20and%20safety%20in%20the%20social%20work%20supervisory%20relationship%20%282017%29.pdf

    https://research-repository.griffith.edu.au/server/api/core/bitstreams/6be4c986-c4d5-5145-9360-6ceb388de953/content

    https://sidneydekker.stackedsite.com/wp-content/uploads/sites/899/2017/09/ZeroVision.pdf

    https://www.academia.edu/download/86424812/j.ssci.2019.09.02820220524-1-1nt6327.pdf

    https://doi.org/10.1016/j.ssci.2018.10.025

    https://journals.sagepub.com/doi/pdf/10.1177/2327857921101130

    https://journals.sagepub.com/doi/pdf/10.1177/25160435211027035?fbclid=IwAR21-3M4frgjnjiiesS5EZCfvfnISjdz7M7P8E130r2NLIPcUrqflEellLk&

    https://doi.org/10.1016/j.ssci.2019.04.039

    https://www.tandfonline.com/doi/pdf/10.1080/09585192.2024.2342294

    https://digitalcommons.osgoode.yorku.ca/cgi/viewcontent.cgi?article=1001&context=ohlj

    https://eprints.lse.ac.uk/109877/1/Noort_et_al._MANUSCRIPT_for_LSE_online.pdf

    https://doi.org/10.1016/j.ssci.2020.105120

    https://www.ida.liu.se/~769A22/Seminarier/articles/safety_counterculture.pdf

    https://doi.org/10.3389/fpsyg.2019.00668

    https://research.vu.nl/ws/portalfiles/portal/2277897/202659.pdf

    https://journals.sagepub.com/doi/pdf/10.1177/0096340211426395

    https://www.researchgate.net/profile/Andrew-Hopkins-4/publication/279759571_The_Limits_of_Normal_Accident_Theory/links/590ef803a6fdccad7b123cb3/The-Limits-of-Normal-Accident-Theory.pdf

    https://www.academia.edu/download/107807207/soc4.1273720231125-1-c3885x.pdf

    https://www.tandfonline.com/doi/pdf/10.1080/1463922X.2021.1881653

    https://www.researchgate.net/profile/Susan-Silbey/publication/228173756_Taming_Prometheus_Talk_About_Safety_and_Culture/links/55103d080cf203521969d837/Taming-Prometheus-Talk-About-Safety-and-Culture.pdf

    https://safety177496371.wordpress.com/2022/02/08/ruthless-exploiters-or-ethical-guardians-of-the-workforce-powerful-ceos-and-their-impact-on-workplace-safety-and-health/

    https://safety177496371.wordpress.com/2025/01/23/safety-culture-and-power-dynamics-in-organizations/

    https://www.researchgate.net/profile/Erin-Stevens-2/publication/350469124_The_impact_of_power_on_health_care_team_performance_and_patient_safety_A_review_of_the_literature/links/608758b98ea909241e28c310/The-impact-of-power-on-health-care-team-performance-and-patient-safety-A-review-of-the-literature.pdf

    https://www.academia.edu/download/110471105/JHQ.000000000000025720240115-1-n29aqn.pdf

    https://www.scielo.br/j/rbso/a/ghnrhMFyqSssFxFFSMfQbXd/?format=pdf&lang=en

    https://dialnet.unirioja.es/descarga/articulo/9554587.pdf

    https://ap-st01.ext.exlibrisgroup.com/61SCU_INST/upload/1741316102864/The%20construction%20and%20legitimation%20of%20workplace%20bullying%20in%20the%20pu.pdf?Expires=1741316223&Signature=itZRT0uJOuRdUpI5C3P6RhfqsmZwlNkxQpZQVbs-OlGf4~VM9H7Hsog9a5Nd3X9WWTDqhARrGVNkArCuMcFeuEg38qP5zQdJzx~V7ldivDFG1IBjRzhKkDD1qPB5-0TSTODiNLdesbPVP6ya-inEspaJZVJuekE6WH5lf-TnDICzt5NS-eMYWxjZBtul1KYSdSNXh55As8qvaHpcDQVZzmUTGO9FJgFjtAJiKL~pyn7E~z5Cj13j-of5IfY~jLA6KNFZ-wrB9YBMLEHzqcsAIudz8QUICkkQYYvG4H8MFEESfS~ShEhvYowHBLg6fS0NzNTOzZBmQ4Ii3JWeoys5OQ__&Key-Pair-Id=APKAJ72OZCZ36VGVASIA

    https://www.academia.edu/download/49166705/j.socscimed.2009.09.05220160927-27290-19a6oxp.pdf

    https://www.academia.edu/download/30990385/2010_Clinical_supervision_Hdez_McDowell.pdf

    https://studystock.wordpress.com/wp-content/uploads/2013/11/understanding-power-in-organizations.pdf

    https://openaccess.city.ac.uk/id/eprint/8236/4/Annals%20accepted.pdf

    https://www.academia.edu/download/89536105/0003-066x.45.2.17920220812-1-11im1f6.pdf

    http://www.contrib.andrew.cmu.edu/~krack/documents/pubs/1990/1990%20Assessing%20the%20Political%20Landscape.pdf

    https://www.academia.edu/download/31144526/administrative_science_quarterly_7_1972_mechanic.pdf

    https://journals.sagepub.com/doi/pdf/10.1177/26317877221084714

    https://ascelibrary.org/doi/pdf/10.1061/%28ASCE%29LM.1943-5630.0000018?download=true

    https://www.researchgate.net/profile/Sean-Buchanan/publication/327477734_Power_Institutions_and_Organizations/links/64888219d702370600ef726d/Power-Institutions-and-Organizations.pdf

    https://www.researchgate.net/profile/Belle-Ragins/publication/232499085_Gender_and_Power_in_Organizations_A_Longitudinal_Perspective/links/56baaf1f08ae3af6847d8c13/Gender-and-Power-in-Organizations-A-Longitudinal-Perspective.pdf

    https://www.researchgate.net/profile/Stewart-Ranson/publication/247733580_Power_and_Advantage_in_Organizations/links/0deec53c68032b4ade000000/Power-and-Advantage-in-Organizations.pdf

    https://citeseerx.ist.psu.edu/document?repid=rep1&type=pdf&doi=c72a7081f0f19c3f3b4e99c492f16ac2f8a21c92

    https://citeseerx.ist.psu.edu/document?repid=rep1&type=pdf&doi=902977fcabe0928dc829ca14ef62a8b26e5b8dad

    https://www.jaapboonstra.nl/wp-content/uploads/2013/01/Power-dynamics-and-organizational-change2.pdf

    https://www.researchgate.net/profile/Jori-Kalkman/publication/308898552_Inter-Organizational_Disaster_Management_Projects_Finding_the_Middle_Way_between_Trust_and_Control/links/5c5a953692851c48a9bd7ccc/Inter-Organizational-Disaster-Management-Projects-Finding-the-Middle-Way-between-Trust-and-Control.pdf

    https://www.humanfactors.lth.se/fileadmin/lusa/Sidney_Dekker/articles/2003_and_before/SuparamaniamDekker2003.pdf

    https://mutualaiddisasterrelief.org/wp-content/uploads/2024/05/The_Biopolitics_of_Disaster_Power_Discourses_and_Practices.pdf

    https://www.diva-portal.org/smash/get/diva2:513208/FULLTEXT01.pdf

    https://onlinelibrary.wiley.com/doi/pdf/10.1002/rhc3.12218

    https://www.researchgate.net/profile/Howard-Schwartz-2/publication/40955166_On_the_psychodynamics_of_organizational_disaster_The_case_of_the_space_shuttle_Challenger/links/5cd08c0a92851c4eab87d179/On-the-psychodynamics-of-organizational-disaster-The-case-of-the-space-shuttle-Challenger.pdf

    https://doi.org/10.1016/j.ssci.2024.106446

    https://link.springer.com/content/pdf/10.1007/s10111-019-00545-8.pdf

    https://www.researchgate.net/profile/Emil-Kotsev/publication/381496413_Managing_the_Distance_with_the_Superior_Toward_a_Resolution_of_a_Subordinate_Manager’s_Dilemma/links/667a797b1dec0c3c6fa322e1/Managing-the-Distance-with-the-Superior-Toward-a-Resolution-of-a-Subordinate-Managers-Dilemma.pdf

    https://www.academia.edu/105928772/Danger_zone_Men_masculinity_and_occupational_health_and_safety_in_high_risk_occupations

    https://scholarlypublications.universiteitleiden.nl/access/item%3A3250217/view

    https://www.ida.liu.se/~769A22/Seminarier/articles/safety_counterculture.pdf

    https://doi.org/10.1016/j.ssci.2020.105120

    https://www.academia.edu/91832217/Power_organization_design_and_managerial_behaviour

    https://journal.psych.ac.cn/acps/EN/Y2022/V54/I5/549

    Abstracts & Extracts

    https://doi.org/10.1016/j.ssci.2008.02.004

    https://asmepublications.onlinelibrary.wiley.com/doi/abs/10.1111/medu.12947

    https://doi.org/10.1016/j.ssci.2013.10.013

    https://doi.org/10.1111/1468-5973.00032

    https://press.princeton.edu/books/paperback/9780691004129/normal-accidents?srsltid=AfmBOorMEgPZMJ-EM2pIOy_Mz1WhKd8IC6z_NGRBcycAgOP7Ktza7r5v

    https://press.uchicago.edu/ucp/books/book/chicago/M/bo3645893.html]

    LinkedIn post: https://www.linkedin.com/pulse/mini-compendium-power-safety-authority-gradients-ben-hutchinson-vttnc

    #accident #authorityGradient #downwardVoice #elites #politics #power #powerGradient #psychologicalSafety #safety #safetyScience #speakingUpToPower #voice

  22. Mini-Compendium: Power, Safety, Authority Gradients, and the Power of Elites

    Here’s some articles, mostly full-text links, exploring power within organisations.

    Includes broader social power, power gradients, voice, and more.

    Feel free to shout me a coffee if you’d like to support the growth of my site:

    https://buymeacoffee.com/benhutchinson

    Full-Text Articles

    [Below link will say ‘Discursive effects of safety science’. Download it and its a whole book with the above chapter]

    https://www.researchgate.net/profile/Johan-Bergstroem/publication/335162893_The_Discursive_Effects_of_Safety_Science/links/650ad3d6d5293c106cca099b/The-Discursive-Effects-of-Safety-Science.pdf#page=124

    https://sidneydekker.com/wp-content/uploads/2024/12/SafetyInPower.pdf

    https://sidneydekker.com/wp-content/uploads/2024/12/JustCultureCritique.pdf

    https://d1wqtxts1xzle7.cloudfront.net/79944444/1d996e_7f6d510450714d16a785e27021ff18b8-libre.pdf?1643583068=&response-content-disposition=inline%3B+filename%3DLeader_Humility_and_Team_Creativity_The.pdf&Expires=1742163884&Signature=dpjnEIAR6EST6HE0kx1~oMIMWZT7p~7tI4qslcYJO9tzlH5l8JsrCpijy4umQXbVzcBvJB799-d~rhpyacjjc0xF-SL0elgOB3llLFvyoWfjBzmEyjKVv8-nmFZNgByEjk9ymu5mzK5W5a9puCm5YBcOolRSmHzoHIlDDNEBxCr-sVGZddRRRxYtYKl83Qau5zlPOJq9nWSe7EIUZcB9-YD6i8jtSwXF5DiStJgRZRvR7ydIWxhKoZwCUe4qUPBAPYZvv3ybYIuARgj7KlEJV8mAPUw3MZSpROLY8YP~m52Yw6lJ8iCZMx2up2xyEi-gyoa2geJjmDaTB6Ic~BbX2g__&Key-Pair-Id=APKAJLOHF5GGSLRBV4ZA

    https://doi.org/10.1016/j.ssci.2024.106446

    https://pmc.ncbi.nlm.nih.gov/articles/PMC4880472/pdf/nihms5702.pdf

    https://www.researchgate.net/profile/Wai-Yoong/publication/362609810_Understanding_authority_gradient_tips_for_speaking_up_for_patient_safety_and_how_to_enhance_the_listening_response/links/67a268e296e7fb48b9b46fa6/Understanding-authority-gradient-tips-for-speaking-up-for-patient-safety-and-how-to-enhance-the-listening-response.pdf

    https://www.researchgate.net/profile/Erin-Stevens-2/publication/350469124_The_impact_of_power_on_health_care_team_performance_and_patient_safety_A_review_of_the_literature/links/608758b98ea909241e28c310/The-impact-of-power-on-health-care-team-performance-and-patient-safety-A-review-of-the-literature.pdf

    https://onlinelibrary.wiley.com/doi/pdf/10.1197/j.aem.2004.07.005

    https://eprints.lse.ac.uk/90953/1/Tear_Safety-culture-and-power.pdf

    https://ecampus.nmit.ac.nz/moodle/pluginfile.php/2178236/mod_resource/content/1/Trust%2C%20Power%20and%20safety%20in%20the%20social%20work%20supervisory%20relationship%20%282017%29.pdf

    https://research-repository.griffith.edu.au/server/api/core/bitstreams/6be4c986-c4d5-5145-9360-6ceb388de953/content

    https://sidneydekker.stackedsite.com/wp-content/uploads/sites/899/2017/09/ZeroVision.pdf

    https://www.academia.edu/download/86424812/j.ssci.2019.09.02820220524-1-1nt6327.pdf

    https://doi.org/10.1016/j.ssci.2018.10.025

    https://journals.sagepub.com/doi/pdf/10.1177/2327857921101130

    https://journals.sagepub.com/doi/pdf/10.1177/25160435211027035?fbclid=IwAR21-3M4frgjnjiiesS5EZCfvfnISjdz7M7P8E130r2NLIPcUrqflEellLk&

    https://doi.org/10.1016/j.ssci.2019.04.039

    https://www.tandfonline.com/doi/pdf/10.1080/09585192.2024.2342294

    https://digitalcommons.osgoode.yorku.ca/cgi/viewcontent.cgi?article=1001&context=ohlj

    https://eprints.lse.ac.uk/109877/1/Noort_et_al._MANUSCRIPT_for_LSE_online.pdf

    https://doi.org/10.1016/j.ssci.2020.105120

    https://www.ida.liu.se/~769A22/Seminarier/articles/safety_counterculture.pdf

    https://doi.org/10.3389/fpsyg.2019.00668

    https://research.vu.nl/ws/portalfiles/portal/2277897/202659.pdf

    https://journals.sagepub.com/doi/pdf/10.1177/0096340211426395

    https://www.researchgate.net/profile/Andrew-Hopkins-4/publication/279759571_The_Limits_of_Normal_Accident_Theory/links/590ef803a6fdccad7b123cb3/The-Limits-of-Normal-Accident-Theory.pdf

    https://www.academia.edu/download/107807207/soc4.1273720231125-1-c3885x.pdf

    https://www.tandfonline.com/doi/pdf/10.1080/1463922X.2021.1881653

    https://www.researchgate.net/profile/Susan-Silbey/publication/228173756_Taming_Prometheus_Talk_About_Safety_and_Culture/links/55103d080cf203521969d837/Taming-Prometheus-Talk-About-Safety-and-Culture.pdf

    https://safety177496371.wordpress.com/2022/02/08/ruthless-exploiters-or-ethical-guardians-of-the-workforce-powerful-ceos-and-their-impact-on-workplace-safety-and-health/

    https://safety177496371.wordpress.com/2025/01/23/safety-culture-and-power-dynamics-in-organizations/

    https://www.researchgate.net/profile/Erin-Stevens-2/publication/350469124_The_impact_of_power_on_health_care_team_performance_and_patient_safety_A_review_of_the_literature/links/608758b98ea909241e28c310/The-impact-of-power-on-health-care-team-performance-and-patient-safety-A-review-of-the-literature.pdf

    https://www.academia.edu/download/110471105/JHQ.000000000000025720240115-1-n29aqn.pdf

    https://www.scielo.br/j/rbso/a/ghnrhMFyqSssFxFFSMfQbXd/?format=pdf&lang=en

    https://dialnet.unirioja.es/descarga/articulo/9554587.pdf

    https://ap-st01.ext.exlibrisgroup.com/61SCU_INST/upload/1741316102864/The%20construction%20and%20legitimation%20of%20workplace%20bullying%20in%20the%20pu.pdf?Expires=1741316223&Signature=itZRT0uJOuRdUpI5C3P6RhfqsmZwlNkxQpZQVbs-OlGf4~VM9H7Hsog9a5Nd3X9WWTDqhARrGVNkArCuMcFeuEg38qP5zQdJzx~V7ldivDFG1IBjRzhKkDD1qPB5-0TSTODiNLdesbPVP6ya-inEspaJZVJuekE6WH5lf-TnDICzt5NS-eMYWxjZBtul1KYSdSNXh55As8qvaHpcDQVZzmUTGO9FJgFjtAJiKL~pyn7E~z5Cj13j-of5IfY~jLA6KNFZ-wrB9YBMLEHzqcsAIudz8QUICkkQYYvG4H8MFEESfS~ShEhvYowHBLg6fS0NzNTOzZBmQ4Ii3JWeoys5OQ__&Key-Pair-Id=APKAJ72OZCZ36VGVASIA

    https://www.academia.edu/download/49166705/j.socscimed.2009.09.05220160927-27290-19a6oxp.pdf

    https://www.academia.edu/download/30990385/2010_Clinical_supervision_Hdez_McDowell.pdf

    https://studystock.wordpress.com/wp-content/uploads/2013/11/understanding-power-in-organizations.pdf

    https://openaccess.city.ac.uk/id/eprint/8236/4/Annals%20accepted.pdf

    https://www.academia.edu/download/89536105/0003-066x.45.2.17920220812-1-11im1f6.pdf

    http://www.contrib.andrew.cmu.edu/~krack/documents/pubs/1990/1990%20Assessing%20the%20Political%20Landscape.pdf

    https://www.academia.edu/download/31144526/administrative_science_quarterly_7_1972_mechanic.pdf

    https://journals.sagepub.com/doi/pdf/10.1177/26317877221084714

    https://ascelibrary.org/doi/pdf/10.1061/%28ASCE%29LM.1943-5630.0000018?download=true

    https://www.researchgate.net/profile/Sean-Buchanan/publication/327477734_Power_Institutions_and_Organizations/links/64888219d702370600ef726d/Power-Institutions-and-Organizations.pdf

    https://www.researchgate.net/profile/Belle-Ragins/publication/232499085_Gender_and_Power_in_Organizations_A_Longitudinal_Perspective/links/56baaf1f08ae3af6847d8c13/Gender-and-Power-in-Organizations-A-Longitudinal-Perspective.pdf

    https://www.researchgate.net/profile/Stewart-Ranson/publication/247733580_Power_and_Advantage_in_Organizations/links/0deec53c68032b4ade000000/Power-and-Advantage-in-Organizations.pdf

    https://citeseerx.ist.psu.edu/document?repid=rep1&type=pdf&doi=c72a7081f0f19c3f3b4e99c492f16ac2f8a21c92

    https://citeseerx.ist.psu.edu/document?repid=rep1&type=pdf&doi=902977fcabe0928dc829ca14ef62a8b26e5b8dad

    https://www.jaapboonstra.nl/wp-content/uploads/2013/01/Power-dynamics-and-organizational-change2.pdf

    https://www.researchgate.net/profile/Jori-Kalkman/publication/308898552_Inter-Organizational_Disaster_Management_Projects_Finding_the_Middle_Way_between_Trust_and_Control/links/5c5a953692851c48a9bd7ccc/Inter-Organizational-Disaster-Management-Projects-Finding-the-Middle-Way-between-Trust-and-Control.pdf

    https://www.humanfactors.lth.se/fileadmin/lusa/Sidney_Dekker/articles/2003_and_before/SuparamaniamDekker2003.pdf

    https://mutualaiddisasterrelief.org/wp-content/uploads/2024/05/The_Biopolitics_of_Disaster_Power_Discourses_and_Practices.pdf

    https://www.diva-portal.org/smash/get/diva2:513208/FULLTEXT01.pdf

    https://onlinelibrary.wiley.com/doi/pdf/10.1002/rhc3.12218

    https://www.researchgate.net/profile/Howard-Schwartz-2/publication/40955166_On_the_psychodynamics_of_organizational_disaster_The_case_of_the_space_shuttle_Challenger/links/5cd08c0a92851c4eab87d179/On-the-psychodynamics-of-organizational-disaster-The-case-of-the-space-shuttle-Challenger.pdf

    https://doi.org/10.1016/j.ssci.2024.106446

    https://link.springer.com/content/pdf/10.1007/s10111-019-00545-8.pdf

    https://www.researchgate.net/profile/Emil-Kotsev/publication/381496413_Managing_the_Distance_with_the_Superior_Toward_a_Resolution_of_a_Subordinate_Manager’s_Dilemma/links/667a797b1dec0c3c6fa322e1/Managing-the-Distance-with-the-Superior-Toward-a-Resolution-of-a-Subordinate-Managers-Dilemma.pdf

    https://www.academia.edu/105928772/Danger_zone_Men_masculinity_and_occupational_health_and_safety_in_high_risk_occupations

    https://scholarlypublications.universiteitleiden.nl/access/item%3A3250217/view

    https://www.ida.liu.se/~769A22/Seminarier/articles/safety_counterculture.pdf

    https://doi.org/10.1016/j.ssci.2020.105120

    https://www.academia.edu/91832217/Power_organization_design_and_managerial_behaviour

    https://journal.psych.ac.cn/acps/EN/Y2022/V54/I5/549

    Abstracts & Extracts

    https://doi.org/10.1016/j.ssci.2008.02.004

    https://asmepublications.onlinelibrary.wiley.com/doi/abs/10.1111/medu.12947

    https://doi.org/10.1016/j.ssci.2013.10.013

    https://doi.org/10.1111/1468-5973.00032

    https://press.princeton.edu/books/paperback/9780691004129/normal-accidents?srsltid=AfmBOorMEgPZMJ-EM2pIOy_Mz1WhKd8IC6z_NGRBcycAgOP7Ktza7r5v

    https://press.uchicago.edu/ucp/books/book/chicago/M/bo3645893.html]

    LinkedIn post: https://www.linkedin.com/pulse/mini-compendium-power-safety-authority-gradients-ben-hutchinson-vttnc

    #accident #authorityGradient #downwardVoice #elites #politics #power #powerGradient #psychologicalSafety #safety #safetyScience #speakingUpToPower #voice

  23. Mini-Compendium: Power, Safety, Authority Gradients, and the Power of Elites

    Here’s some articles, mostly full-text links, exploring power within organisations.

    Includes broader social power, power gradients, voice, and more.

    Feel free to shout me a coffee if you’d like to support the growth of my site:

    https://buymeacoffee.com/benhutchinson

    Full-Text Articles

    [Below link will say ‘Discursive effects of safety science’. Download it and its a whole book with the above chapter]

    https://www.researchgate.net/profile/Johan-Bergstroem/publication/335162893_The_Discursive_Effects_of_Safety_Science/links/650ad3d6d5293c106cca099b/The-Discursive-Effects-of-Safety-Science.pdf#page=124

    https://sidneydekker.com/wp-content/uploads/2024/12/SafetyInPower.pdf

    https://sidneydekker.com/wp-content/uploads/2024/12/JustCultureCritique.pdf

    https://d1wqtxts1xzle7.cloudfront.net/79944444/1d996e_7f6d510450714d16a785e27021ff18b8-libre.pdf?1643583068=&response-content-disposition=inline%3B+filename%3DLeader_Humility_and_Team_Creativity_The.pdf&Expires=1742163884&Signature=dpjnEIAR6EST6HE0kx1~oMIMWZT7p~7tI4qslcYJO9tzlH5l8JsrCpijy4umQXbVzcBvJB799-d~rhpyacjjc0xF-SL0elgOB3llLFvyoWfjBzmEyjKVv8-nmFZNgByEjk9ymu5mzK5W5a9puCm5YBcOolRSmHzoHIlDDNEBxCr-sVGZddRRRxYtYKl83Qau5zlPOJq9nWSe7EIUZcB9-YD6i8jtSwXF5DiStJgRZRvR7ydIWxhKoZwCUe4qUPBAPYZvv3ybYIuARgj7KlEJV8mAPUw3MZSpROLY8YP~m52Yw6lJ8iCZMx2up2xyEi-gyoa2geJjmDaTB6Ic~BbX2g__&Key-Pair-Id=APKAJLOHF5GGSLRBV4ZA

    https://doi.org/10.1016/j.ssci.2024.106446

    https://pmc.ncbi.nlm.nih.gov/articles/PMC4880472/pdf/nihms5702.pdf

    https://www.researchgate.net/profile/Wai-Yoong/publication/362609810_Understanding_authority_gradient_tips_for_speaking_up_for_patient_safety_and_how_to_enhance_the_listening_response/links/67a268e296e7fb48b9b46fa6/Understanding-authority-gradient-tips-for-speaking-up-for-patient-safety-and-how-to-enhance-the-listening-response.pdf

    https://www.researchgate.net/profile/Erin-Stevens-2/publication/350469124_The_impact_of_power_on_health_care_team_performance_and_patient_safety_A_review_of_the_literature/links/608758b98ea909241e28c310/The-impact-of-power-on-health-care-team-performance-and-patient-safety-A-review-of-the-literature.pdf

    https://onlinelibrary.wiley.com/doi/pdf/10.1197/j.aem.2004.07.005

    https://eprints.lse.ac.uk/90953/1/Tear_Safety-culture-and-power.pdf

    https://ecampus.nmit.ac.nz/moodle/pluginfile.php/2178236/mod_resource/content/1/Trust%2C%20Power%20and%20safety%20in%20the%20social%20work%20supervisory%20relationship%20%282017%29.pdf

    https://research-repository.griffith.edu.au/server/api/core/bitstreams/6be4c986-c4d5-5145-9360-6ceb388de953/content

    https://sidneydekker.stackedsite.com/wp-content/uploads/sites/899/2017/09/ZeroVision.pdf

    https://www.academia.edu/download/86424812/j.ssci.2019.09.02820220524-1-1nt6327.pdf

    https://doi.org/10.1016/j.ssci.2018.10.025

    https://journals.sagepub.com/doi/pdf/10.1177/2327857921101130

    https://journals.sagepub.com/doi/pdf/10.1177/25160435211027035?fbclid=IwAR21-3M4frgjnjiiesS5EZCfvfnISjdz7M7P8E130r2NLIPcUrqflEellLk&

    https://doi.org/10.1016/j.ssci.2019.04.039

    https://www.tandfonline.com/doi/pdf/10.1080/09585192.2024.2342294

    https://digitalcommons.osgoode.yorku.ca/cgi/viewcontent.cgi?article=1001&context=ohlj

    https://eprints.lse.ac.uk/109877/1/Noort_et_al._MANUSCRIPT_for_LSE_online.pdf

    https://doi.org/10.1016/j.ssci.2020.105120

    https://www.ida.liu.se/~769A22/Seminarier/articles/safety_counterculture.pdf

    https://doi.org/10.3389/fpsyg.2019.00668

    https://research.vu.nl/ws/portalfiles/portal/2277897/202659.pdf

    https://journals.sagepub.com/doi/pdf/10.1177/0096340211426395

    https://www.researchgate.net/profile/Andrew-Hopkins-4/publication/279759571_The_Limits_of_Normal_Accident_Theory/links/590ef803a6fdccad7b123cb3/The-Limits-of-Normal-Accident-Theory.pdf

    https://www.academia.edu/download/107807207/soc4.1273720231125-1-c3885x.pdf

    https://www.tandfonline.com/doi/pdf/10.1080/1463922X.2021.1881653

    https://www.researchgate.net/profile/Susan-Silbey/publication/228173756_Taming_Prometheus_Talk_About_Safety_and_Culture/links/55103d080cf203521969d837/Taming-Prometheus-Talk-About-Safety-and-Culture.pdf

    https://safety177496371.wordpress.com/2022/02/08/ruthless-exploiters-or-ethical-guardians-of-the-workforce-powerful-ceos-and-their-impact-on-workplace-safety-and-health/

    https://safety177496371.wordpress.com/2025/01/23/safety-culture-and-power-dynamics-in-organizations/

    https://www.researchgate.net/profile/Erin-Stevens-2/publication/350469124_The_impact_of_power_on_health_care_team_performance_and_patient_safety_A_review_of_the_literature/links/608758b98ea909241e28c310/The-impact-of-power-on-health-care-team-performance-and-patient-safety-A-review-of-the-literature.pdf

    https://www.academia.edu/download/110471105/JHQ.000000000000025720240115-1-n29aqn.pdf

    https://www.scielo.br/j/rbso/a/ghnrhMFyqSssFxFFSMfQbXd/?format=pdf&lang=en

    https://dialnet.unirioja.es/descarga/articulo/9554587.pdf

    https://ap-st01.ext.exlibrisgroup.com/61SCU_INST/upload/1741316102864/The%20construction%20and%20legitimation%20of%20workplace%20bullying%20in%20the%20pu.pdf?Expires=1741316223&Signature=itZRT0uJOuRdUpI5C3P6RhfqsmZwlNkxQpZQVbs-OlGf4~VM9H7Hsog9a5Nd3X9WWTDqhARrGVNkArCuMcFeuEg38qP5zQdJzx~V7ldivDFG1IBjRzhKkDD1qPB5-0TSTODiNLdesbPVP6ya-inEspaJZVJuekE6WH5lf-TnDICzt5NS-eMYWxjZBtul1KYSdSNXh55As8qvaHpcDQVZzmUTGO9FJgFjtAJiKL~pyn7E~z5Cj13j-of5IfY~jLA6KNFZ-wrB9YBMLEHzqcsAIudz8QUICkkQYYvG4H8MFEESfS~ShEhvYowHBLg6fS0NzNTOzZBmQ4Ii3JWeoys5OQ__&Key-Pair-Id=APKAJ72OZCZ36VGVASIA

    https://www.academia.edu/download/49166705/j.socscimed.2009.09.05220160927-27290-19a6oxp.pdf

    https://www.academia.edu/download/30990385/2010_Clinical_supervision_Hdez_McDowell.pdf

    https://studystock.wordpress.com/wp-content/uploads/2013/11/understanding-power-in-organizations.pdf

    https://openaccess.city.ac.uk/id/eprint/8236/4/Annals%20accepted.pdf

    https://www.academia.edu/download/89536105/0003-066x.45.2.17920220812-1-11im1f6.pdf

    http://www.contrib.andrew.cmu.edu/~krack/documents/pubs/1990/1990%20Assessing%20the%20Political%20Landscape.pdf

    https://www.academia.edu/download/31144526/administrative_science_quarterly_7_1972_mechanic.pdf

    https://journals.sagepub.com/doi/pdf/10.1177/26317877221084714

    https://ascelibrary.org/doi/pdf/10.1061/%28ASCE%29LM.1943-5630.0000018?download=true

    https://www.researchgate.net/profile/Sean-Buchanan/publication/327477734_Power_Institutions_and_Organizations/links/64888219d702370600ef726d/Power-Institutions-and-Organizations.pdf

    https://www.researchgate.net/profile/Belle-Ragins/publication/232499085_Gender_and_Power_in_Organizations_A_Longitudinal_Perspective/links/56baaf1f08ae3af6847d8c13/Gender-and-Power-in-Organizations-A-Longitudinal-Perspective.pdf

    https://www.researchgate.net/profile/Stewart-Ranson/publication/247733580_Power_and_Advantage_in_Organizations/links/0deec53c68032b4ade000000/Power-and-Advantage-in-Organizations.pdf

    https://citeseerx.ist.psu.edu/document?repid=rep1&type=pdf&doi=c72a7081f0f19c3f3b4e99c492f16ac2f8a21c92

    https://citeseerx.ist.psu.edu/document?repid=rep1&type=pdf&doi=902977fcabe0928dc829ca14ef62a8b26e5b8dad

    https://www.jaapboonstra.nl/wp-content/uploads/2013/01/Power-dynamics-and-organizational-change2.pdf

    https://www.researchgate.net/profile/Jori-Kalkman/publication/308898552_Inter-Organizational_Disaster_Management_Projects_Finding_the_Middle_Way_between_Trust_and_Control/links/5c5a953692851c48a9bd7ccc/Inter-Organizational-Disaster-Management-Projects-Finding-the-Middle-Way-between-Trust-and-Control.pdf

    https://www.humanfactors.lth.se/fileadmin/lusa/Sidney_Dekker/articles/2003_and_before/SuparamaniamDekker2003.pdf

    https://mutualaiddisasterrelief.org/wp-content/uploads/2024/05/The_Biopolitics_of_Disaster_Power_Discourses_and_Practices.pdf

    https://www.diva-portal.org/smash/get/diva2:513208/FULLTEXT01.pdf

    https://onlinelibrary.wiley.com/doi/pdf/10.1002/rhc3.12218

    https://www.researchgate.net/profile/Howard-Schwartz-2/publication/40955166_On_the_psychodynamics_of_organizational_disaster_The_case_of_the_space_shuttle_Challenger/links/5cd08c0a92851c4eab87d179/On-the-psychodynamics-of-organizational-disaster-The-case-of-the-space-shuttle-Challenger.pdf

    https://doi.org/10.1016/j.ssci.2024.106446

    https://link.springer.com/content/pdf/10.1007/s10111-019-00545-8.pdf

    https://www.researchgate.net/profile/Emil-Kotsev/publication/381496413_Managing_the_Distance_with_the_Superior_Toward_a_Resolution_of_a_Subordinate_Manager’s_Dilemma/links/667a797b1dec0c3c6fa322e1/Managing-the-Distance-with-the-Superior-Toward-a-Resolution-of-a-Subordinate-Managers-Dilemma.pdf

    https://www.academia.edu/105928772/Danger_zone_Men_masculinity_and_occupational_health_and_safety_in_high_risk_occupations

    https://scholarlypublications.universiteitleiden.nl/access/item%3A3250217/view

    https://www.ida.liu.se/~769A22/Seminarier/articles/safety_counterculture.pdf

    https://doi.org/10.1016/j.ssci.2020.105120

    https://www.academia.edu/91832217/Power_organization_design_and_managerial_behaviour

    https://journal.psych.ac.cn/acps/EN/Y2022/V54/I5/549

    Abstracts & Extracts

    https://doi.org/10.1016/j.ssci.2008.02.004

    https://asmepublications.onlinelibrary.wiley.com/doi/abs/10.1111/medu.12947

    https://doi.org/10.1016/j.ssci.2013.10.013

    https://doi.org/10.1111/1468-5973.00032

    https://press.princeton.edu/books/paperback/9780691004129/normal-accidents?srsltid=AfmBOorMEgPZMJ-EM2pIOy_Mz1WhKd8IC6z_NGRBcycAgOP7Ktza7r5v

    https://press.uchicago.edu/ucp/books/book/chicago/M/bo3645893.html]

    LinkedIn post: https://www.linkedin.com/pulse/mini-compendium-power-safety-authority-gradients-ben-hutchinson-vttnc

    #accident #authorityGradient #downwardVoice #elites #politics #power #powerGradient #psychologicalSafety #safety #safetyScience #speakingUpToPower #voice

  24. I rewrote some of the tragedy I've been working on moving from Shakespeare's 16th century to Morvelet's Fifth Era.

    You see, Morvelet didn't write in Eorzean. Or even Early Modern Eorzean. He wrote in Middle Eorzean. And so his REAL language goes a little like this:

    Ye blockes, ye stones, ye duller than bestaille!
    O ye harde hertes, ye felouns of Allage,
    Knewe ye nat Pompêy? Many a tyme and ofte
    Have ye y-clumben up to mansiouns hye,
    To railes and landing paddes, ye, to vent-stackes,
    Your infantes in your armes, and ther have sat
    Al the longe day, with pacient expectacioun,
    To seen grete Pompêy passe the stretes of Allage.

    Read more: taper-project.jijivisa.org/#fi

    Yeah. I fucking turned Shakespeare into Morvelet into FUCKING CHAUCER, then I kept the iambic pentameter anyway.

    I can do motherfucking ANYTHING! 🎆

    #TheTaperProject #BardOfSagon #Morvelet #FFXIVWrite #MiddleEorzean #IambicPentameter #Prosody #Linguistics #Chaucer #FFXIVLore #Worldbuilding #CreativeWriting #Allagan #Sharlayan #WritingCommunity

  25. I rewrote some of the tragedy I've been working on moving from Shakespeare's 16th century to Morvelet's Fifth Era.

    You see, Morvelet didn't write in Eorzean. Or even Early Modern Eorzean. He wrote in Middle Eorzean. And so his REAL language goes a little like this:

    Ye blockes, ye stones, ye duller than bestaille!
    O ye harde hertes, ye felouns of Allage,
    Knewe ye nat Pompêy? Many a tyme and ofte
    Have ye y-clumben up to mansiouns hye,
    To railes and landing paddes, ye, to vent-stackes,
    Your infantes in your armes, and ther have sat
    Al the longe day, with pacient expectacioun,
    To seen grete Pompêy passe the stretes of Allage.

    Read more: taper-project.jijivisa.org/#fi

    Yeah. I fucking turned Shakespeare into Morvelet into FUCKING CHAUCER, then I kept the iambic pentameter anyway.

    I can do motherfucking ANYTHING! 🎆

    #TheTaperProject #BardOfSagon #Morvelet #FFXIVWrite #MiddleEorzean #IambicPentameter #Prosody #Linguistics #Chaucer #FFXIVLore #Worldbuilding #CreativeWriting #Allagan #Sharlayan #WritingCommunity