%% Qunpack.m
% Qube_osf.m unpacks itself.
    fin = fopen("Qube_osf.m",'r');
    mkdir("Qube");
    L = fgetl(fin);
    while ~isequal(L,'%% EOF')
        F = ['Qube/' L(4:end)];
        disp(F)
        fout = fopen(F,'w');
        L = fgetl(fin);
        while length(L) < 2 || ~isequal(L(1:2),'%%')
            fprintf(fout,'%s\n',L);
            L = fgetl(fin);
        end
        fclose(fout);
    end
    fclose(fin);
%% Qube.m
function Qube(ops)
%  Linear algebra and computer science combine to power Rubik's cube. 
%  Most recent edit: '19-May-2022 06:00'
%  info: https://blogs.mathworks.com/cleve/2022/02/13/rubiks-cube
%        https://blogs.mathworks.com/cleve/2022/04/04/digital-simulation-of-rubiks-cube/
%        https://blogs.mathworks.com/cleve/2022/04/12/digital-simulation-of-rubiks-cube-with-Qube/
%        https://blogs.mathworks.com/cleve/2022/05/04/qube-the-movie/
%        https://blogs.mathworks.com/cleve/2022/05/18/rotation-matrices/
%
%  L R U D F B X Y Z: rotate clockwise, Singmaster notation,
%           Left, Right, Up, Down, Front, Back, x, y, z axes.
%  '   :    Rotate counter-clockwise.
%  <=  :    Apply inverse of most recent rotation.
%  =>  :    Redo most recent <=.
%  <== :    Unscramble, repeated <=.
%  ~~> :    Scramble, repeated random rotations.  
%  ==> :    Apply stack again.  
%  Q0  :    Initial cube.
%  period:  Number of repetitions required to return to Q0.
%  solve:   Experimental solver.
%  delta:   Fractional rotation, controls speed.
%  type:    Center=0, face=1, edge=2, corner=3.
%  restart: Complete restart.      
%
%  Q: cube, 3x3x3 array of 8x3 vertices of cubelets.     
%  Q0: initial cube showing a single color on each face.
%  op: one of the keys, followed by a blank, a prime or a 2.
%  score: nuclear norm = sum of svd(Q{j}-Q0{j}).
%  stack: string of ops displayed in a window above the cube.
%  starting conditions: Q = Q0, empty stack.
%
%    Copyright 2022 Cleve Moler

    if nargin == 0
        Qfigure
        Qinit
        Qshow
        shg
    else
        shg
        ops = split(string(ops))';
        for k = 1:length(ops)
            key([char(ops(k)) ' '])
        end
    end
end
%% Q0.m
function Q = Q0(~,~)

    v = 0.90*qzero;
        
    Q = cell(3,3,3);
    for z = [-2 0 2]
        for y = [-2 0 2]
            for x = [-2 0 2]
                Q{x/2+2,y/2+2,z/2+2} = v + [x y z];
            end
        end 
    end

    if nargin == 2
        Qshow(Q)
        qstate('Q',Q)
        show_stack('')
        qstate('stack','')
    end
end
%% Qfigure.m
function Qfigure(scale)
    if nargin < 1
        scale = 4;
    end
    % Initialize figure window for Rubik's cube
    clf
    set(gcf,'name','Qube, 19-May-2022', ...
        'numbertitle','off', ...
        'toolbar','none', ...
        'menubar','none', ...
        'color',0.75*[1 1 1], ...
        'userdata',{})
    %{
    set(gcf,'windowbuttondownfcn',@wdownf, ...
        'windowbuttonupfcn',@wupf)
    %}

    set(gca,'position',[1/3 7/24 1/2 1/2], ...
        'vis','on', ...
        'clipping','off')
    axis(scale*[-1 1 -1 1 -1 1])
    axis('square','off','vis3d')
    rotate3d off
    view(3)
    shg

end
%% Qinit.m
function Qinit
    
    u = 60;
    alfa = 'LRUDFBXYZ';  % Singmaster alphabet
    for j = 1:9
        x = 4*j+2*(j>6)+8;
        pushbut([alfa(j)  ' '],[x 6 3 3]/u, @key)
        pushbut([alfa(j) ''''],[x 2 3 3]/u, @key)
    end

    pushbut(      "<=", [ 2  2 6 3]/u, @bs)
    toggbut(     "<==", [ 2  6 6 3]/u, @unscramble)
    pushbut(    "type", [ 2 14 6 3]/u, @typescb)
    pushbut(   "delta", [ 2 18 6 3]/u, @deltacb)
    
    pushbut(      "=>", [53  2 6 3]/u, @fs)
    pushbut(     "==>", [53  6 6 3]/u, @once)
    toggbut(     "~~>", [53 10 6 3]/u, @scramble)

    toggbut(     "gif", [53 22 6 3]/u, @gifcb)
    pushbut(      "Q0", [53 26 6 3]/u, @Q0)
    pushbut( "restart", [53 30 6 3]/u, @restarter)
    toggbut(   "solve", [53 34 6 3]/u, @Qsolve)
    toggbut(  "period", [53 42 6 3]/u, @Qperiod)
    
    textbut(  "pcount", [53 46 6 3]/u, "pcount")
    textbut(     "ops", [ 2 54 6 3]/u, "ops")
    textbut(   "score", [53 54 6 3]/u, "score")
    pushbut(      " ", [12 54 38 3]/u, @stacker)
    framed_mat(        [ 2 29 16 11]/u)

    tooltips
    rng('shuffle')
end
%% Qmove.m
    function Q = Qmove(op,Q)
    if op(2) == '2'
        op(2) = ' ';
        Q = Qmove(op,Q);
        Q = Qmove(op,Q);
        return
    end
    if op(1) == 'N'
        % Null
        d = 1;
        f = 1;
        sig = 0;
        return
    else
        [d,f,sig] = dfsig(op);
    end
    Qsave = Q;
  
    % Fractional steps
    delta = qstate('delta');
    for n = 1:90/abs(delta)
        R = Rk(d,sig*n*delta);
        Q = Qrot(Qsave,d,f,R);
        Qshow(Q)
        if qstate('gif') == 1
            gif_frame
        else
            drawnow
        end
    end

    % Full quarter turn, +/- 90 degrees.
    Q = Qsave; 
    for i = f
        switch d
            case 1,Q(i,:,:) = quarter(sig,d,Q(i,:,:));
            case 2,Q(:,i,:) = quarter(sig,d,Q(:,i,:));
            case 3,Q(:,:,i) = quarter(sig,d,Q(:,:,i));
        end
    end
    
    Qshow(Q)
    Qscore(Q)
    
end
%% Qnorm.m
function nrm = Qnorm(X,Y)
    % Qnorm(X,Y) = sum of singular values of X-Y. 
    % Also known as nuclear norm.
    nrm = 0;
    for j = 1:27
        nrm = nrm + sum(svd(X{j}-Y{j}));
    end
end
%% Qpack.m
function Qpack
    fout = fopen('../Qube_osf.m','w');
    d = dir;
    d = string({d.name})';
    d(d=="Qunpack.m") = [];
    d(d=="Qube.m") = [];
    d(1) = "Qunpack.m";
    d(2) = "Qube.m";
    for F = d'
        disp(F)
        fprintf(fout,'%%%% %s\n',F);
        fin = fopen(F,'r');
        L = fgetl(fin);
        while ~isequal(L,-1)
            fprintf(fout,'%s\n',L);
            L = fgetl(fin);
        end
        fclose(fin);
    end
    fprintf(fout,'%%%% %s\n','EOF');
    fclose(fout);
end
%% Qperiod.m
function Qperiod(arg,~)
    if nargin == 0
        arg = @Qperiod;
    end
    v = arg.Value;
    arg.BackgroundColor = 1-v*[.70 .25 .07];
    counter = findobj('tag','pcount');
    ops = findobj('tag','ops');
    ops.String = '0';
    period = 0; 
    Qshow(Q0)
    qstate('Q',Q0)
    nrm = inf;
    while nrm > 0 && arg.Value > 0 
        once
        nrm = Qnorm(qstate('Q'),Q0);
        period = period+1;
        counter.String = int2str(period);
        drawnow
    end
    arg.Value = 0;
    arg.BackgroundColor = 'w'; 
end
%% Qrot.m
function Q = Qrot(Q,d,f,R)
    switch d
        case 1
            for j = 1:3
                for k = 1:3
                    for i = f
                        Q{i,j,k} = Q{i,j,k}*R;
                    end
                end
            end
        case 2
            for j = 1:3
                for k = 1:3
                    for i = f
                        Q{k,i,j} = Q{k,i,j}*R;
                    end
                end
            end
        case 3
            for j = 1:3
                for k = 1:3
                    for i = f
                        Q{k,j,i} = Q{k,j,i}*R;
                    end
               end
            end
    end
end
%% Qscore.m
function Qscore(Q)
    counter = findobj('tag','ops');
    scorer = findobj('tag','score');
    nrm = Qnorm(Q,Q0);
    if ~isempty(counter)
        counter.Value = counter.Value + 1;
        counter.String = num2str(counter.Value);
    end
    if ~isempty(scorer)
        scorer.String = sprintf('%7.2f',round(nrm,2));
        scorer.FontName = 'Lucisa Sans Typewriter';
        scorer.FontWeight = 'bold';
    end
end
%% Qshow.m
function Qshow(Q)
% Qshow(Q)  Display Q.  Default qstate('Q')

    if nargin == 0
        Q = qstate('Q');
    end

    C = [0   0  3/4    % blue
        3/4  0   0     % red
         1   1   1     % white
         0  3/4  0     % green
         1  3/5  0     % orange
         1   1   0];   % yellow

    F = [1 5 7 3
         3 7 8 4
         1 3 4 2
         2 4 8 6
         1 2 6 5
         5 6 8 7];

    gps = get(gcf,'pos');
    lw = 1 + 0.5*(gps(4) > 400);

    set(gca,'userdata',Q)
    cla
    j = 0;
    for x = [-2 0 2]
        for y = [-2 0 2]
            for z = [-2 0 2]
                j = j + 1;
                nz = nnz([x y z]);
                if types(nz) && j <= numel(Q) 
                    for k = 1:6 
                        patch( ...
                            Vertices = Q{j}, ...
                            Faces = F(k,:), ...
                            FaceColor = C(k,:), ...
                            UserData = [nz j k], ...
                            LineWidth = lw); 
                    end
                end
            end
        end
    end
end
%% Qsolve.m
function Qsolve(arg,arg2,Qin,soln)
    alfa = 'LRUDFB';
    counter = findobj('tag','ops');
    scorer = findobj('tag','score');
    if nargin == 2
        Qin = qstate('Q');
        soln = '';
        arg.BackgroundColor = colors(6);
        counter.Value = 0;
        counter.String = num2str(counter.Value);
        poster.String = qstate('stack');
    end
    Q1 = Qin;
    nrm1 = Qnorm(Q1,Q0);
    scorer.String = sprintf('%7.2f',nrm1);
    for k = 1:6
        for s = [' ','''']
            op = [alfa(k) s];
            Q = Qmove(op,Qin);
            nrm = Qnorm(Q,Q0);
            scorer.String = sprintf('%7.2f',nrm);
            if nrm < nrm1 || arg.Value == 0
                soln = [op soln];
                break
            end
        end
        if nrm < nrm1 || arg.Value == 0
            break
        end
    end
    if nrm == 0
        % solution
        arg.BackgroundColor = 'w'; 
    elseif nrm == nrm1 || arg.Value == 0
        % fail
        arg.BackgroundColor = [.64 .08 .18];
    else
        % recur
        counter.Value = counter.Value + 1;
        counter.String = num2str(counter.Value);
        Qsolve(arg,arg2,Q,soln);
    end
    qstate('stack',soln)
    show_stack(soln)
    Qshow(Q0)
    arg.Value = 0;
end
%% Rk.m
function R = Rk(k,d)
    % Rk(k,d) is rotation by d degrees about k-th axis.
    c = cosd(d); 
    s = sind(d);
    switch k
        case 1, R = [ 1  0  0  
                      0  c  s
                      0 -s  c ];
        case 2, R = [ c  0  s  
                      0  1  0
                     -s  0  c ];
        case 3, R = [ c  s  0  
                     -s  c  0
                      0  0  1 ];
    end
    fmat = findobj('tag','fmat');
    if ~isempty(fmat)
        fmat.String = mat3(R);
    end
end
%% bs.m
function bs(~,~)
% bs, backspace, inverse of first op in stack
    op = pop;
    if ~isempty(op)
        Q = qstate('Q');
        opt = transposer(op);
        Q = Qmove(opt,Q);
        qstate('Q',Q)
        qstate('stack2',[qstate('stack2') op])
    end  
end
%% deltacb.m
function deltacb(arg,~)
    % delta, fractional rotation.
    switch arg.String
        case '3', delta = '6';
        case '6', delta = '15';
        case '15', delta = '30';
        case '30', delta = '90';
        case '90', delta = 'inf';
        case 'inf', delta = '3';
        otherwise, delta = '30';
    end
    arg.String = delta;
    qstate('delta',str2double(delta))
    Qshow(qstate('Q'))
end
%% dfsig.m
function [d,f,sig] = dfsig(op)
% [d,f,sig] = dfsig(op), d-th dimennsion, f-th face.
    [a,~] = view;
    a = mod(round((a+37.5)/90),4);
    switch a
        case 0
            W = ["L" "M" "R" "X"
                 "F" "S" "B" "Y"
                 "D" "E" "U" "Z"]; 
                opsm = 'RFUYZSE';
        case 1
            W = ["B" "S" "F" "Y"
                 "L" "M" "R" "X"
                 "D" "E" "U" "Z"];
                opsm = 'LFUXYZMSE';
        case 2
            W = ["R" "M" "L" "X"
                 "B" "S" "F" "Y"
                 "D" "E" "U" "Z"]; 
                opsm = 'LBUXZME';
        case 3
            W = ["F" "S" "B" "Y"
                 "R" "M" "L" "X"
                 "D" "E" "U" "Z"];
                opsm = 'RBUZE';
    end
    [d,f] = find(op(1)==W);
    if f == 4
        f = 1:3;
    end
    sig = 2*(op(2) == ' ')-1;
    if any(op(1) == opsm)
        sig = -sig;
    end
end
%% framed_mat.m
function framed_mat(pos)
    uicontrol( ...
        'style','frame', ...
        'units','normalized', ...
        'position',pos, ...
        'backgroundcolor',0.25*[1 1 1])
    
    del = .003;
    uicontrol( ...
        'style','text', ...
        'units','normalized', ...
        'position',pos+[del del -2*del -2*del], ...
        'fontname','Lucida Sans Typewriter', ...
        'fontsize',9, ...
        'fontweight','bold', ...
        'horizontalalignment','left', ...
        'backgroundcolor','w', ...
        'string',mat3(eye(3,3)), ...
        'tag','fmat')
end
%% fs.m
function fs(~,~)
% fs.  "forward space" 
    op = pop2;  % first op in stack2
    if ~isempty(op)
        Q = qstate('Q');
        Q = Qmove(op,Q);
        push(op)
        qstate('Q',Q)
        show_stack(qstate('stack'))
    end  
end
%% gifcb.m
function gifcb(arg,~)
    if nargin == 0
        arg = findobj('callback',@gifscb);
    end
    qstate('gif',arg.Value)
end
%% key.m
function key(arg,~)
    if nargin == 2
        op = arg.String;
    else
        op = arg;
    end
    Q = qstate('Q');
    Q = Qmove(op,Q);
    push(op)
    qstate('Q',Q)
end
%% last.m
function lst = last(s)
   % indices of last op in stack    
   k = find((s ~= ' ') & (s ~= ''''),2,'last');
   if length(k) > 1
       lst = k(2):length(s);
   else
       lst = 1:length(s);
   end
end
%% mat3.m
function txt = mat3(M)
    txt = newline;
    for k = 1:3
        for j = 1:3
            if M(k,j) == 0
                txt = [txt sprintf('%6.0f',abs(M(k,j)))];
            elseif M(k,j) == round(M(k,j))
                txt = [txt sprintf('%6.0f',M(k,j))];
            else
                txt = [txt sprintf('%6.2f',M(k,j))];
            end
        end
        txt = [txt newline];
    end
end
%% once.m
function once(~,~)
    stk2 = blanks(0);
    while ~isempty(peek)
        stk2 = [stk2 pop];
    end
    Q = qstate('Q');
    Qshow(Q)
    while ~isempty(stk2)
        tp = top(stk2);
        op = stk2(tp);
        stk2(tp) = [];
        Q = Qmove(op,Q);
        push(op)
        show_stack(qstate('stack'))
    end
    qstate('Q',Q)
end
%% peek.m
function op = peek
    % peek   return top op
    stk = qstate('stack');
    tp = top(stk);
    op = stk(tp);
end
%% pop.m
function op = pop
    % pop   remove op from top of stack
    stk = qstate('stack');
    tp = top(stk);
    op = stk(tp);
    stk(tp) = []; % delete top element
    show_stack(stk)
    qstate('stack',stk)
end
%% pop2.m
function op = pop2
    % pop2   remove op from top of stack2
    stk = qstate('stack2');
    tp = top(stk);
    op = stk(tp);
    stk(tp) = []; % delete top element
    qstate('stack2',stk)
end
%% push.m
function push(op,~)
    % push  insert op on top  of stack
    stk = qstate('stack');
    op(op==' ') = [];
    op = [op ' '];
    stk = [stk op];
    show_stack(stk)
    qstate('stack',stk)
end 
%% pushbut.m
function pushbut(string,position,callback,varargin)
    uicontrol(Style = "pushbutton", ...
        String = string, ...
        Units = "normalized", ...
        Position = position, ...
        Callback = callback, ...
        Fontsize = 10, ...
        Fontweight = "bold", ...
        BackgroundColor = 'w');
end
%% qstate.m
function vout = qstate(name,vin)
    % qstate(name,set_value)
    % get_value = qstate(name)
    
    names = {'Q','stack','stack2','delta','type','gif'}; 
    defaults = {Q0, '', '', 30, 0:3, 0};
    
    state = get(gcf,'userdata');
    if isempty(state)
        state = defaults;
        set(gcf,'userdata',defaults)
    end
    for k = 1:length(names)
        if isequal(name,names{k})
            if nargin == 2
                state{k} = vin;
                set(gcf,'userdata',state)
            else
                vout = state{k};
            end
            return
        end
    end
end
%% quarter.m
function Fout = quarter(sig,d,F)
    F = squeeze(F);
    R = Rk(d,sig*90);
    for j = 1:3
        for i = 1:3
            if sig < 0
                Fout{j,4-i} = F{i,j}*R;
            else
                Fout{4-j,i} = F{i,j}*R;
            end
        end
    end
end
%% qzero.m
function q0 = qzero
    % Unit cubelet.
    q0 = [-1 -1 -1
          -1 -1  1
          -1  1 -1
          -1  1  1
           1 -1 -1
           1 -1  1
           1  1 -1 
           1  1  1];
end
%% randdo.m
function randdo(~,~)
    op = random_op;
    Q = qstate('Q');
    Q = Qmove(op,Q);
    push(op)
    qstate('Q',Q)
end
%% random_op.m
function op = random_op
    alfa = 'LMRUEDFSBXYZ';
    alfa = 'LRUDFB';
    op = blanks(2);
    op(1) = alfa(randi(length(alfa)));
    if rand > 0.5
        op(2) = '''';
    end
end
%% restarter.m
function restarter(~,~)
    Qube
end
%% scramble.m
function scramble(arg,~)
    if nargin == 0
        arg = findobj('tag','scramble');
    end
    v = arg.Value;
    arg.BackgroundColor = 1-v*[.70 .25 .07];
    while arg.Value > 0
        randdo(arg)
        drawnow
    end
    arg.BackgroundColor = 'w';
end
%% show_stack.m
function show_stack(stk)
    stacker = findobj('callback',@stacker);
    if ~isempty(stacker)
        stacker.String = stk;
    end
end
%% stacker.m
function stacker(arg,~)
    arg.String = '';
    qstate('stack','')
end
%% textbut.m
function textbut(string,position,tag)
    uicontrol(Style = "pushbutton", ...
        String = string, ...
        Units = "normalized", ...
        Position = position, ...
        Tag = tag, ...
        Fontsize = 10, ...
        Fontweight = "bold", ...
        BackgroundColor = 'w');
end
%% toggbut.m
function toggbut(str,position,callback)
    v = isequal(str,' ''');
    uicontrol(Style = "toggle", ...
        String = str, ...
        Units = "normalized", ...
        Position = position, ...
        Callback = callback, ... 
        Value = v, ...
        Fontsize = 10, ...
        Fontweight = "bold", ...
        BackgroundColor = 'w');
end
%% tooltips.m
function tooltips
    tip = @(x,y,z) set(findobj(x,y),'tooltip',z);
    tip("string",   "=>",     "Redo most recent <=.")
    tip("string",   "~~>",    "Scramble with repeated random rotations.")
    tip("string",   "==>",    "Apply stack again.")
    tip("string",   "<=",     "Apply inverse of most recent rotation.") 
    tip("string",   "<==",    "Unscramble with repeated <=.")
    tip("string",   "solve",  "Experimental solver.")
    tip("string",   "period", "Number of repetitions to return to Q0.")
    tip("string",   "period", "Number of repetitions to return to Q0.")
    tip("string",   "Q0",     "Q0, clear stack.")
    tip("string",   "gif",    "Animated diary.")
    tip("string",   "restart","Call Qube.")
    tip("tag",      "score",  "Nuclear norm distance to Q0.")
    tip("tag",      "ops",    "Total number of ops.")
    tip("tag",      "pcount", "period.")
    tip("callback", @stacker, "Stack of ops, click to clear")
    tip("callback", @deltacb, "Fractional step in rotation.")
    tip("callback", @typescb, "Show center, face, edge, corner cubelets.")
end
%% top.m
function top = top(s)
   % indices of first op in stack    
   k = find((s ~= ' ') & (s ~= '''') & (s ~= '2'),2,'last');
   if length(k) > 1
       top = k(2):length(s);
   else
       top = 1:length(s);
   end
end
%% transposer.m
function op = transposer(op)
    % op = op'
    if isempty(op)
        return
    elseif isscalar(op)
        op = [op char(' ' + '''' - op)];         
    else
        op(2) = char(' ' + '''' - op(2));
    end
end
%% types.m
function t = types(arg)
    % cubelet type
    t = ismember(arg,qstate('type'));
end
%% typescb.m
function typescb(arg,~)
    if nargin == 0
        arg = findobj('callback',@typescb);
    end
    switch arg.String
        case '2:3', s = '0:3';
        case '0:3', s = '0:2';
        case '0:2', s = '0:1';
        case '0:1', s = '0';
        case '0',   s = '1';
        case '1',   s = '2';
        case '2',   s = '3';
        case '3',   s = '2:3';
        otherwise,  s = '0:3';
    end
    arg.String = s;
    qstate('type',eval(s))
    Qshow
end
%% unscramble.m
function unscramble(arg,~)
% undo.  bs until stack is empty.
    while arg.Value > 0 && ~isempty(peek)
        bs(arg)
        drawnow
    end
    arg.BackgroundColor = 'w'; 
    arg.Value = 0;
end
%% viewcb.m
function viewcb(arg,~)
    if arg.Value == 1           
        arg.BackgroundColor = [.30 .75 .93];
        rotate3d on
    else
        arg.BackgroundColor = 'w';
        [a,~] = view;
        a = 90*round((a+37.5)/90)-37.5;
        e = 30;
        view([a,e])
        rotate3d off 
    end
end
%% wbmf.m
function wbmf(~,~)
   %set(gcf,'windowbuttondownfcn',[])
   %set(gcf,'windowbuttonmotionfcn',[])
   %co = get(gcf,'currentobject'); 
   cp = get(gca,'currentpoint');
   %ud = co.UserData;
   %k = ud(3);
   k = 4;
   y = cp(1,2);
   x = cp(1,1);
   switch k
       case 4
           % U
           d = 3;
           f = 3;
       case 3
           % L
           d = 1;
           f = 1;
       case 5
           % F
           d = 2;
           f = 1;
   end
   theta = atan2d(y,x);
   Q = qstate('Q');
   Q = Qrot(Q0,d,f,90-Rk(d,theta));
   Qshow(Q)
   qstate('Q',Q)
end
%% wdownf.m
function w = wdownf(src,~)
    % window button down fcn
    set(gcf,'windowbuttonmotionfcn',@wbmf)
    %{
    seltype = src.SelectionType;
    if strcmp(seltype,'normal')
        cp = get(gca,'currentpoint');
        co = get(gcf,'currentobject');
        ud = co.UserData;
        set(gcf,'windowbuttonmotionfcn',@wbmf)
        set(gcf,'windowbuttonupfcn',@wupf)
    end
    %}
end
%% wupf.m
function w = wupf(~,~)
    % window button up fcn
    set(gcf,'windowbuttonmotionfcn',[])
    set(gcf,'windowbuttondownfcn',@wdownf)
end
%% EOF