[Question]
  [
A Window is an ASCII-art square with odd side length of at least 3, with a single character border around the edge as well as vertical and horizontal strokes in the middle:
```
#######
#  #  #
#  #  #
#######
#  #  #
#  #  #
#######
```
An MS Window is a window where the border is made only of the characters `M` and `S`. Your task is to write a program (or function) that takes a string and outputs a truthy value if the input is a valid MS Window, and a falsey value if it is not.
# Specifications
* You may take the input as a newline-separated string or an array of strings representing each line.
* The border of an MS Window may contain a mix of M and S characters, but the inside will always be composed of spaces.
* You can choose to detect only windows with trailing newlines, or only windows without trailing newlines, but not both.
# Test Cases
Truthy:
```
MMM
MMM
MMM
SMSMS
M M S
SMSMM
S S M
SMSMS
MMMMMMM
M  S  M
M  S  M
MSSSSSM
M  S  M
M  S  M
MMMMMMM
```
Falsey:
```
Hello, World!
MMMM
MSSM
MS M
MMMM
MMSMM
M S.M
sSSSS
M S M
MMSMM
MMMMMMM
M  M  M
MMMMMMM
M  M  M
MMMMMMM
MMMMMMM
M M M M
MMMMMMM
M M M M
MMMMMMM
M M M M
MMMMMMM
MMSSMSSMM
M   M   M
S   S   S
S   S  S
MMSSMSSMM
S   S   S
S   S   S
M   M   M
MMSSMSSMM
```
  
[Answer]
## [Retina](https://github.com/m-ender/retina), ~~68~~ 67 bytes
Byte count assumes ISO 8859-1 encoding.
```
S
M
^(M((M)*M)\2)((?<-9>¶M((?<9-3> )*(?(3)!)M|\5)\5)*(?(9)!)¶\1)\4$
```
[Try it online!](https://tio.run/nexus/retina#jU4xDsIwDNz9ilQCya4oEhSGqqhdWW7ywBIhBtgqKsHKu/qAfqzEbUEV6kAcxz7f5RJ/p5z0kue05FA6JdCZwQyJIX4rzOUhyYq2gXVZkhZOYi45lUjw8nsJ23AWcNv4jfjdousA0CdJEYLgQsz0pkGvdU6dm1S1NTMf9XS8VVW9cqf6UV2jwccu2THKbKi9ta5BT/Ozvmd1oL9vY@r9iyfE8Pc/8Rs "Retina – TIO Nexus")
[Answer]
## [Grime](https://github.com/iatorm/grime), ~~39~~ 38 bytes
*Thanks to Zgarb for saving 1 byte.*
```
e`BB/BB/W+ W/+
B=W|B/W\ * W/\ /*
W=[MS
```
[Try it online!](https://tio.run/nexus/grime#@5@a4OSkD0Th2grh@tpcTrbhNUBOjIIWkBujoK/FFW4b7Rv8/78vBHD5KigEKygg0cEggEUcAgA "Grime – TIO Nexus")
I'm not sure whether there's a simpler way to enforce the square aspect ratio of the individual window components than using a recursive nonterminal, but this seems to be working quite well.
### Explanation
It's best to read the program from the bottom up.
```
W=[MS
```
This simply defines a nonterminal (which you can think of as a subroutine that matches a rectangle) `W` which matches either an `M` or an `S` (there's an implicit `]` at the end of the line).
```
B=W|B/W\ * W/\ /*
```
This defines a non-terminal `B` which matches about a quarter of the output, i.e. one window panel with the left and top border. Something like this:
```
MSM
S  
M  
```
To ensure that this window panel is square, we define `B` recursively. It's either a window character `W`, or it's `B/W\ * W/\ /*` which adds one layer to the right and to the bottom. To see how it does this, let's remove some syntactic sugar:
```
(B/W[ ]*)(W/[ ]/*)
```
This is the same, because horizontal concatenation can be written either `AB` or `A B`, but the latter has lower precedence than the vertical concatenation `/` while for the former has higher. So `B/W[ ]*` is a `B` with a window character and a row of spaces below. And then we horizontally append `W/[ ]/*` which is a window character with a column of spaces.
Finally, we assemble these nonterminals into the final window shape:
```
BB/BB/W+ W/+
```
That's four window panels `B` followed by a row of window characters and a column of window characters. Note that we make no explicit assertion that the four window panels are the same size, but if they aren't it's impossible to concatenate them into rectangle.
Finally the `e`` at the beginning is simply a configuration which tells Grime to check that the entire input can be matched by this pattern (and it prints `0` or `1` accordingly).
[Answer]
## JavaScript (ES6), ~~115~~ 113 bytes
```
a=>(l=a.length)&a.every((b,i)=>b.length==l&b.every((c,j)=>(i&&l+~i-i&&l+~i&&j&&l+~j-j&&l+~j?/ /:/[MS]/).test(c)))
```
Takes input as a an array of arrays of characters (add 5 bytes for an array of strings) and returns `1` or `0`. After verifying that the height is odd, every row is checked to ensure the array is square, and every character is verified to be one of the character(s) that we expect in that particular position. Edit: Saved 2 bytes thanks to @PatrickRoberts.
[Answer]
# Perl, ~~124~~ ~~123~~ ~~119~~ ~~95~~ ~~93~~ 84
The following Perl script reads one candidate MS Window from the standard input. It then exits with a zero exit status if the candidate is an MS Window and with a non-zero exit status if it isn't.
It works by generating two regular expressions, one for the top, middle and bottom line and one for every other line, and checking the input against them.
Thanks, @Dada. And again.
```
map{$s=$"x(($.-3)/2);$m="[MS]";($c++%($#a/2)?/^$m$s$m$s$m$/:/^${m}{$.}$/)||die}@a=<>
```
[Answer]
# Mathematica, 166 bytes
```
Union[(l=Length)/@data]=={d=l@#}&&{"M","S"}~(s=SubsetQ)~(u=Union@*Flatten)@{#&@@(p={#,(t=#~TakeDrop~{1,-1,d/2-.5}&)/@#2}&@@t@#),p[[2,All,1]]}&&{" "}~s~u@p[[2,All,2]]&
```
Unnamed function taking a list of lists of characters as input and returning `True` or `False`. Here's a less golfy version:
```
(t = TakeDrop[#1, {1, -1, d/2 - 0.5}] &; 
Union[Length /@ data] == {d = Length[#1]}
  &&
(p = ({#1, t /@ #2} &) @@ t[#1];
SubsetQ[{"M", "S"}, Union[Flatten[{p[[1]], p[[2, All, 1]]}]]]
  && 
SubsetQ[{" "}, Union[Flatten[p[[2, All, 2]]]]])) &
```
The first line defines the function `t`, which separates a list of length `d` into two parts, the first of which is the first, middle, and last entries of the list, and the second of which is all the rest. The second line checks whether the input is a square array in the first place. The fourth line uses `t` twice, once on the input itself and once on all\* of the strings in the input, to separate the characters that are supposed to be `"M"` or `"S"` from the characters that are supposed to be spaces; then the fifth and seventh lines check whether they really are what they're supposed to be.
[Answer]
## JavaScript (ES6), ~~108~~ 106 bytes
Input: array of strings / Output: `0` or `1`
```
s=>s.reduce((p,r,y)=>p&&r.length==w&(y==w>>1|++y%w<2?/^[MS]+$/:/^[MS]( *)[MS]\1[MS]$/).test(r),w=s.length)
```
### Test cases
```
let f =
s=>s.reduce((p,r,y)=>p&&r.length==w&(y==w>>1|++y%w<2?/^[MS]+$/:/^[MS]( *)[MS]\1[MS]$/).test(r),w=s.length)
console.log('Testing truthy test cases...');
console.log(f([
  'MMM',
  'MMM',
  'MMM'
]));
console.log(f([
  'SMSMS',
  'M M M',
  'SMSMS',
  'M M M',
  'SMSMS'
]));
console.log(f([
  'MMMMMMM',
  'M  S  M',
  'M  S  M',
  'MSSSSSM',
  'M  S  M',
  'M  S  M',
  'MMMMMMM'
]));
console.log('Testing falsy test cases...');
console.log(f([
  'Hello, World!'
]));
console.log(f([
  'MMMM',
  'MSSM',
  'MS M',
  'MMMM'
]));
console.log(f([
  'MMSMM',
  'M S.M',
  'sSSSS',
  'M S M',
  'MMSMM'
]));
console.log(f([
  'MMMMMMM',
  'M  M  M',
  'MMMMMMM',
  'M  M  M',
  'MMMMMMM'
]));
console.log(f([
  'MMMMMMM',
  'M M M M',
  'MMMMMMM',
  'M M M M',
  'MMMMMMM',
  'M M M M',
  'MMMMMMM'
]));
```
[Answer]
# JavaScript (ES6), ~~140~~ ~~138~~ ~~141~~ 140 bytes
I know this isn't a winning byte count (although thanks to Patrick Roberts for -3, and I realised it threw false positives for 1 instead of M/S: +3), but I did it a slightly different way, I'm new to this, and it was fun...
Accepts an array of strings, one for each line and returns true or false. Newline added for clarity (not included in byte count).
```
f=t=>t.every((e,i)=>e.split`S`.join`M`==[...p=[b='M'.repeat(s=t.length),
...Array(z=-1+s/2|0).fill([...'MMM'].join(' '.repeat(z)))],...p,b][i])
```
Instead of checking input against a generalised pattern, I construct an 'M' window of the same size, replace S with M on input, and compare the two.
## Ungolfed
```
f = t => t.every( // function returns true iff every entry in t
                  // returns true below
  (e, i) => e.split`S`.join`M` // replace all S with M
                                 // to compare to mask
  == [ // construct a window of the same size made of Ms and
       // spaces, compare each row 
      ...p = [ // p = repeated vertical panel (bar above pane)
               // which will be repeated
              b = 'M'.repeat(s = t.length),
                  // b = bar of Ms as long as the input array
              ...Array(z = -1 + s/2|0).fill([...'MMM'].join(' '.repeat(z)))],
              // z = pane size; create enough pane rows with
              // Ms and enough spaces
      ...p, // repeat the panel once more
      b][i] // finish with a bar
)
console.log(f(["111","111","111"]))
console.log(f(["MMMMM","M S M","MSSSM","M S M","MSSSM"]))
```
## Test cases
```
f=t=>t.every((e,i)=>e.split`S`.join`M`==[...p=[b='M'.repeat(s=t.length),
...Array(z=-1+s/2|0).fill([...'MMM'].join(' '.repeat(z)))],...p,b][i])
truthy=`MMM
MMM
MMM
SMSMS
M M M
SMSMS
M M M
SMSMS
MMMMMMM
M  S  M
M  S  M
MSSSSSM
M  S  M
M  S  M
MMMMMMM`.split('\n\n')
falsey=`Hello, World!
MMMM
MSSM
MS M
MMMM
MMSMM
M S.M
sSSSS
M S M
MMSMM
MMMMMMM
M  M  M
MMMMMMM
M  M  M
MMMMMMM
MMMMMMM
M M M M
MMMMMMM
M M M M
MMMMMMM
M M M M
MMMMMMM`.split('\n\n')
truthy.forEach(test=>{
  console.log(test,f(test.split('\n')))
})
falsey.forEach(test=>{
  console.log(test,f(test.split('\n')))
})
```
[Answer]
## Pyke, ~~34~~ 31 bytes
```
lei}t\Mcn+it*i\M*+s.XM"QJ\S\M:q
```
[Try it here!](http://pyke.catbus.co.uk/?code=lei%7Dt%5CMcn%2Bit%2ai%5CM%2a%2Bs.XM%22QJ%5CS%5CM%3Aq&input=%22MMMMM%22%2C%22M+M+M%22%2C%22MMSMM%22%2C%22M+M+M%22%2C%22MMMMM%22)
```
lei                              -         i = len(input)//2
   }t                            -        (^ * 2) - 1
     \Mc                         -       "M".center(^)
        n+                       -      ^ + "\n"
          it*                    -     ^ * (i-1)
                 +               -    ^ + V
             i\M*                -     "M"*i
                  s              -   palindromise(^)
                   .XM"          -  surround(^, "M")
                               q - ^ == V
                       QJ        -   "\n".join(input)
                         \S\M:   -  ^.replace("S", "M")
```
[Answer]
# JavaScript (ES6), ~~109~~ ~~107~~ ~~106~~ ~~105~~ 99 bytes
```
s=>!s.split`S`.join`M`.search(`^((M{${r=s.search`
`}})(
(M( {${w=(r-3)/2}})M\\5M
){${w}}))\\1\\2$`)
```
**Edit**: Whoa, Arnauld saved me 6 bytes by changing `s.split`\n`.length` to `s.search`\n``! Thanks!
This takes a single multiline string and constructs a `RegExp`-based validation using the length of the input string. Returns `true` or `false`. Assumes a valid window ~~has~~ *does not have* a trailing newline.
# Demo
```
f=s=>!s.split`S`.join`M`.search(`^((M{${r=s.search`
`}})(
(M( {${w=(r-3)/2}})M\\5M
){${w}}))\\1\\2$`);
`MMM
MMM
MMM
SMSMS
M M M
SMSMS
M M M
SMSMS
MMMMMMM
M  S  M
M  S  M
MSSSSSM
M  S  M
M  S  M
MMMMMMM
Hello, World!
MMMM
MSSM
MS M
MMMM
MMSMM
M S.M
sSSSS
M S M
MMSMM
MMMMMMM
M  M  M
MMMMMMM
M  M  M
MMMMMMM
MMMMMMM
M M M M
MMMMMMM
M M M M
MMMMMMM
M M M M
MMMMMMM`.split`
`.forEach(test=>{console.log(test,f(test));});
```
]