user
Create a password generation program which will generate passwords containing random ASCII characters from the following groups:

```
         lower-case letters:  a ──► z
         upper-case letters:  A ──► Z
                     digits:  0 ──► 9
 other printable characters:  !"#$%&'()*+,-./:;<=>?@[]^_{|}~ 
 (the above character list excludes white-space, backslash and grave) 

```

The generated password(s) must include   *at least one*   (of each of the four groups):

```
   lower-case letter, 
   upper-case letter,
   digit  (numeral),   and 
   one  "other"  character. 

```

The user must be able to specify the password length and the number of passwords to generate.

The passwords should be displayed or written to a file, one per line.

The randomness should be from a system source or library.

The program should implement a help option or button which should describe the program and options when invoked.

You may also allow the user to specify a seed value, and give the option of excluding visually similar characters.

For example:            Il1     O0     5S     2Z            where the characters are:

:   :   :   :   * capital eye, lowercase ell, the digit one
                * capital oh, the digit zero
                * the digit five, capital ess
                * the digit two, capital zee
assistant
(formerly Perl 6)

**Works with**: Rakudo version 2016.05

```
my @chars =
  set('a' .. 'z'),
  set('A' .. 'Z'),
  set('0' .. '9'),
  set(<!"#$%&'()*+,-./:;<=>?@[]^_{|}~>.comb);

# bleh. unconfuse syntax highlighter. '"

sub MAIN ( Int :$l = 8, Int :$c = 1, Str :$x = '' ) {
    note 'Password length must be >= 4' and exit if $l < 4;
    note 'Can not generate fewer than 0 passwords' and exit if $c < 0;
    my $chars = [∪] @chars».=&filter;
    note 'Can not exclude an entire required character group' and exit
      if any(@chars».elems) == 0;
    for ^$c {
        my @pswd;
        @pswd.push( @chars[$_].roll ) for ^4;
        @pswd.push( $chars    .roll ) for 4 ..^ $l;
        say [~] @pswd.pick(*);
    }

    sub filter (Set $set) { $set ∖ set($x.comb) }
}

sub USAGE() {
    say qq:to/END/;
    Specify a length:              --l=8 (default 8),
    Specify a count:               --c=1 (default 1),
    Specify characters to exclude: --x=
    (must escape characters significant to the shell)
    E.G.
    {$*PROGRAM-NAME} --l=14 --c=5 --x=0O\\\"\\\'1l\\\|I
    END
}

```

**Sample output:**
Using defaults:

```
c?6!xU+u
```

With passed parameters: --l=14 --c=5 --x=0O\'\"1l\|I

```
6H~jC+5(+&H44x
+Rr}2>htHMa.Y9
t~#&N]sp_zGK2#
TcP73CJ@euFMjj
9%-tYX]z?8-xA5
```

### functional

```
my @char-groups =
    ['a' .. 'z'],
    ['A' .. 'Z'],
    ['0' .. '9'],
    < $ % & \ ` ~ ! * + , - . / :  ;  = ? @ ^ _  ~ [ ] ( ) { | } # ' " \< \> >.Array;

subset MinimumPasswordLength of  Int where * >= 4;
subset NumberOfPasswords     of UInt where * != 0;

sub MAIN( NumberOfPasswords :c(:$count) = 1, MinimumPasswordLength :l(:$length) = 8, Str :x(:$exclude) = '' ) {
    &USAGE() if 1 == (.comb ∖ $exclude.comb).elems for @char-groups; 
    .say for password-characters($length, $exclude )
        .map( *.split(' ') )
        .map( *.pick: Inf ) # shuffle, so we don't get a predictable pattern
        .map( *.join )
        .head( $count );
}

sub password-characters( $len, $exclude ) {
    ( (( char-groups($exclude)       xx Inf ).map: *.pick).batch(     4)
     Z~
      (( char-groups($exclude, $len) xx Inf ).map: *.pick).batch($len-4) )
}

multi char-groups( $exclude )              { | @char-groups.map( * (-) $exclude.comb ) }
multi char-groups( $exclude, $max-weight ) { flat (char-groups($exclude)>>.keys.map: {$_ xx ^$max-weight .roll}) }

sub USAGE() {
    say qq:to/END/;
    Specify a length:              -l=10    (minimum 4)
    Specify a count:               -c=5     (minimum 1)
    Specify characters to exclude: -x=xkcd  (optional)
    Password must have at least one of each: lowercase letter, uppercase letter, digit, punctuation.
   END
}

```

**Sample output:**

Without parameters:

```
d[G2r4;i
```

With passed parameters: -c=5 -l=12 -x=aeiou

```
x7)YbEZQ2xp2
CEpZ>#4'rO7d
pn(5B;wb66DM
KA;3T7=s+I5{
LL<tB~L1~Y*q
```