Posted on Jan 14, 2012

No Correct Answer

Don't you think that there are times when the questions are designed so that it's impossible to have the correct answer?

And that life sometimes follows suit?

Posted on Nov 23, 2011

Ctrl Slash on OSX Emacs

I've been scouring the net, upturning each pebble and stone, looking for a solution to the DONK sound I get everytime I hit CTRL + / on the emacs terminal, so that I could perform one of the most basic tasks prone to men, the UNDO. The alternative is to use CTRL+SHIFT+PLUS, but it irks me that once in the office, I'll have to go back to CTRL+/. For a while I tried avoiding mistakes as much as possible, but DANG, to err is really human. What a futile attempt that was. Google wasn't so omnicient this time. I was so happy to find a question Google couldn't help me with. All the forums I've found had zit for an answer.

But here I'll share the small golden nugget of an app that's used for a bunch of other things. Fixing the "osx emacs ctrl slash" bug problem maybe form ust 1 percent of its full capabilities.

The answer lies in key remaps using a system preference addition called keyRemap4MacBook. Don't let the name fool you. It works on all OSX installations, including Lion.

I'm currently typing this post on my osx emacs and happily making mistakes knowing I could always hit my undo button and not need to have acrobatic fingers to do so. All I had to do was go to Emacs Mode->Behavior in Emacs..->[Terminal] Control+/ to C-_...

Posted on Jun 11, 2011

Posting from Emacs Shell

So this is the first post I have using the shell command that I made that'll post to word press Smile. I am happy! I decided to use emacs since I wish to be well accustomed to its writing environment anyway. And it's got a shell version that is ultra fast. And it's customizable. I could make hooks to it for python to run. This is amazing. It ports my knowledge in python into this app thats new to me.

Here is a sample image of a shell running emacs. I'm typing this post on something similar. I wrote scripts for it so that it'll post this message to my wordpress. And in the scripts I added some basic decorating effects so that the image above would automatically have the html tags for an image to display properly. I have something going also for youtube and vimeo videos.
Besides, this is just a test.

Posted on Jun 8, 2011

Posting from Shell

I'm writing this post for two reasons. First, I'd like to try out posting using from a linux shell. Secondly, I'd like to document my what I'm doing.

Everyone's been crazy-gaga over how easy it is to learn most apps because of their gorgeous intuitive interfaces. I'm not against that. But for the time it takes to navigate your cursor from one part of the screen, to click file, and then open, and then all the clicking through your folders and folders to get the file on c: named 'hello.txt', I've already typed 'open hello.txt,' and in fact, I'm looking at it already.

All those clicks can be burdensome. It helps for the learning slope, but it makes everything else slow.

I am in an working environment where people surf the web without using the mouse. They write scripts without even using cursor keys. Their palms have permanent rests. You could cuff, no, sorry not cuff, clamp their hands to the keyboard from 9am to 6pm, and they wouldn't even notice it. I exaggerate. But I'm not that far from the truth. Besides, it helps in the office ergonomics. In any case, these guys are amazing.

And for all the beauty OSX has that Windows hopes to have, linux has the shell. It's for that reason I looked for a way to type my tweets using shell commands. If you will type it anyway, why not type your tweets where people have been typing ever since. A shell is available anywhere instantly on a linux.

Right now, I'm writing this text on a python script that'll post to my wordpress. The script is being written on emacs -nw. It's a crude setup for now, but it should be enough to test things. I wish to post videos and have my wordpress download hotlinked images.

To see if video posting will work, I took a random clip from vimeo. I haven't seen it. Hope it is nothing offensive.

If you wish to know more about this, why dont you try checking Vizible's Blog. That's where I got my initial idea (my basic script), anyway. I'll work on the posted script he had and turn it into a personal poster for myself.

Posted on May 3, 2011

MikeyMike’s Fix For The Rolling Shutter

The Rolling Shutter is a VFX heartbreaker. Most of the today's cameras house the more economical CMOS image sensor as opposed to CCD. CMOS is larger than the CCD and it uses less energy. But for a VFX artist who will have to matchmove the shot prior to anything else, the CMOS is a killer. The CMOS works a lot like a photocopying machine. If you notice on photocopiers, there is a bright line of light that starts on one side of the glass plate and moves to the opposite side. On the CMOS camera, this bright line of light is done electronically on the sensor's plate and it is more a line that gathers information from the lenses. It's an opening of information, rather than a bright light. And its starts from above rather than from one side. But it is the same in all other respects.

Just like in photocopying, so long as the book you are duplicating remains steady, you won't have a problem. If things move, we see a smear in the copy. This same effect is visible when you use a CMOS camera to shoot for footage.

Here's an example video:

On a CCD, the entire frame is taken in one instant, like a flash of brilliance. Unfortunately, it's consumes more energy. The sensor I think is also more expensive to manufacture, not that I propose on making it ourselves. Most of todays cameras are CMOS.

Essential to the matchmoving process is being able to pinpoint locations of certain points or features of an image sequence exactly for any given frame or point in time. That was a mouth full. But there lies the problem with trying to matchmove a smeared image sequence. For any given frame, the top of the frame was not taken in same point in time as the bottom part of the image. So matchmoving software are given imperfect data to solve. There solutions would therefore be faulty. Aside from the fact that smeared images look odd and in most cases ugly.

So if you understood the process, you could imply that if one could simply tell matchmoving software that the 2D trackers given to it are not all recorded in the same instant, that in fact there are variables of offsets in time, then it shouldn't have any trouble handling the data properly. For this though, one has to find ways to communicate with these software. Most of which allow for scripting.

If you are not the type who enjoy talking to computers or applications, you'll be interested in MikeyMike's way cool innovative makeshift to solve this problem. He does it in the image level though. So it'll be very process intensive, but if it works the first time, you'll only have to do it once.

MikeyMike from vimeo, came up with this make shift way to get rid of the effect.

BTW: The downside of only having the offsets noted in the matchmoving software's level is, your outputs from your 3dsoftware will have to be rendered out with the offsets in in effect as well. It will be a little like rendering to fields for PAL users. It would be nice to write something like this. I would claim this as project I would like to finish before the end of the year.

Posted on Apr 28, 2011

House of Cards

I'm no rock fan. Neither am I especially endeared to the band Radiohead. I prefer my morning commute free of unwanted music. As much as I enjoy apple i-products, I think pluggin earphones in your ears is unnecessary. We don't need to add an Official Soundtrack to our lives. I prefer silence and the ambient street sounds if there'd be any.

I am a fan of Technology. And here is an artsy demonstration of some old mathematical concepts, something that thrills me to the core.

I've heard of Double Negative using LIDAR technology to plot building facade proportions. They'll use this intelligent camera to find out exact positions of random points that hit an environment. I've seen the results of these in Maya files, filled with locators, of the exact proportion of the real buildings. I knew I would have wanted to get my hands on a LIDAR camera. But here's the next best thing.

Radiohead has an MTV filled with animated LIDAR data ANDDDD you could even download the LIDAR results as CSVs (comma-separted value files) so that you could write your own visualization program of the animation. Hmmmm.. Click on the above pic to see the app.

Posted on Dec 30, 2010

A New Toy

HP MINI

I am writing this post on my new Ubuntu running HP Mini 210. With this tastey piece of machinery I will write posts for my blog and scripts for Python. It is so lightweight it makes my iPhone seem a bit heavy (okay, that was exaggerated). I was planning on hackintosh-ing an OSX on it, but it was too cumbersome. There were too many incompatibilities and I wasn't up to the challenge. So, to learn for Object-C, I'll have to ressurect my old macbook. For that I'll need to a new charger and, if I want to go airborn, a new battery pack. Both past away due to old age. I hope the machinery is still in tact.

Posted on Nov 23, 2010

Jay-Dee Alpha Stage

Jay-Dee Python Scribbler
An app that allows one to load video files and draw on them. (Previously known as PyScribbler)

How to use:
All you need to do is load an image sequence or movie file (and/or an audio file). Try to load small short sequences or videos at first.

You can use your middle button to scrub through the time line. Using your left button allows you to draw.

You could also use the left and right arrow keys to step one frame forward and backward.

Once you've drawn enough into the images, you could hit the export button and save the file. The button is right beside the help button.

Help me out:
Don't forget to help me out with feedback. I'm interested in what shortcuts you think it should have or which features it shouldn't miss. I also expect it to be able to open all kinds of files. But in the event that you are having trouble loading certain files, let me know. I'd like to have a list of file-type it could load and file-types it couldn't yet.

I would greatly appreciate your feedback. I believe this program, once it reaches it's maturity, would be an app that all animators would love to have.

Download:

How to Install:

Download the file. Then extract to a directory of your choice. Run the program jaydee.exe from the 'bin' folder, under the folder you selected. Viola! You are ready!

Feature List:

  1. Draw on Video
  2. Draw on Image Sequence
  3. Export Video
  4. Export to Image
  5. Frame-by-frame playback
  6. Replace Sound
  7. Wild-range of Video Formats
  8. Onion Skin

Future Feature List:

  1. Import from Youtube and Vimeo
  2. Draw on multiple frames at a time
  3. Points that follow features on video
  4. Write text

Features To Do List:

  1. Image Sequence Load Function
  2. Audio Load Function
  3. Movie Load Function
  4. Movie Load with Intelligent Audio Add
  5. Play/Pause/Reverse Functions
  6. Next/Previous Frame Functions
  7. Go to Start/End Function
  8. Enable/Disable Loop/PingPong
  9. Mute/Unmute Function
  10. Scrubbing with timeslider, current framebox, middlebuttondrag
  11. Frame Change
  12. Zoom function and scrollbars
  13. Draw onto image
  14. Draw onto image with color selectors
  15. Draw onto image with different size brushes
  16. Draw onto image with a wacom with pressure control
  17. Save project (Researching for this, I won't and can't use cPickle. But I found a QDataStream example from pagedesigner.pyw.. oh Yeah!)
  18. Export to movie
  19. A better GUI for loading images. Statusbar updates won't be satisfactory for this.
  20. The better gui should have image previews of images being loaded into memory
  21. Better scrollbar focus preservation. Cuz when zooming in, scrollbars would default to the center. Not nice.
  22. A yes/no dialog box that would ask if audio found in movies should be loaded.
  23. Better zoom implementation. Something that doesn't lag when in zoomed in.
  24. Change GUI to use PyQT Toolbars. They are awesome. I wish I had the foresight to use them from the start.
  25. Soft brushstrokes and erase.
  26. List down all the process that were started, and monitor them. Make sure they are all dead before the app quits.
  27. Cancelling imports needs to readjust framecounts

Shortcuts:

  • Pencil Tool (Q)
  • Erase Tool (E)
  • Zoom Tool (Z)
  • Onion Skin Toggle (O)
  • Pingpong Loop Toggle (P)
  • Cycle Loop Toggle (L)
  • Step One Frame Forward (Right Arrow)
  • Step One Frame Back (Left Arrow)
  • Pause/Play (Space)
  • Pause/Play Reverse (Shift + Space)
  • Go to Start Frame (Home)
  • Go to Last Frame (End)

If you have ideas or suggestions, please leave a comment!

Jay-Dee Python Scribbler
========================
This is an app that allows one to load video files and draw on them.

How to use:
-----------
All you need to do is load an image sequence or movie file (and/or an audio file). Try to load small short sequences or videos at first.

You can use your middle button to scrub through the time line. Using your left button allows you to draw.

You could also use the left and right arrow keys to step one frame forward and backward.

Once you've drawn enough into the images, you could hit the export button and save the file. The button is right beside the help button.

Help me out:
Don't forget to help me out with feedback. I'm interested in what shortcuts you think it should have or which features it shouldn't miss. I also expect it to be able to open all kinds of files. But in the event that you are having trouble loading certain files, let me know. I'd like to have a list of file-type it could load and file-types it couldn't yet.

I would greatly appreciate your feedback. I believe this program, once it reaches it's maturity, would be an app that all animators would love to have.

Things added after first first version:
---------------------------------------
1. Image Sequence Load Function
2. Audio Load Function
3. Movie Load Function
4. Movie Load with Intelligent Audio Add
5. Play/Pause/Reverse Functions
6. Next/Previous Frame Functions
7. Go to Start/End Function
8. Enable/Disable Loop/PingPong
9. Mute/Unmute Function
10. Scrubbing with timeslider, current framebox, middlebuttondrag
11. Frame Change
12. Zoom function and scrollbars
13. Draw onto image
14. Draw onto image with color selectors
15. Draw onto image with different size brushes
16. Draw onto image with a wacom with pressure control
17. Save project (Researching for this, I won't and can't use cPickle. But I found a QDataStream
    example from pagedesigner.pyw.. oh Yeah!)
18. Export to movie
19. A better GUI for loading images. Statusbar updates won't be satisfactory for this.
20. The better gui should have image previews of images being loaded into memory
21. Better scrollbar focus preservation. Cuz when zooming in, scrollbars would
    default to the center. Not nice.

Future Features:
----------------
1. A yes/no dialog box that would ask if audio found in movies should be loaded.
2. Better zoom implementation. Something that doesn't lag when in zoomed in.
3. Change GUI to use PyQT toolbars. They are awesome. I wish I had the foresight to use them
   from the start.
4. Soft brushstrokes and erase
5. List down all the process that were started, and monitor them. Make sure they are all dead
   before the app quits.

Things I'll definately do before beta release:
----------------------------------------------
1. Fix the menu and short-cuts
2. Cancelling imports needs to readjust framecounts

For comments and suggestions, please send to redesigndavid at gmail dot com. Thanks!!!

Posted on Oct 29, 2010

Row 1 Not Found, List Deformer Dialog Alternative

I'm not sure what causes it, but often when trying to produce the List Deformer Dialog Box in Maya, I get this

// Error: file: C:/Program Files/Autodesk/Maya2011/scripts/others/detachHistoryTable.mel line 369: Object 'row1' not found.

So I decided to write an alternative, using my jd_listOfOrderedDeformers as base.

// this procedure will return a list of deformers ordered
global proc string[] jd_listOfOrderedDeformers () {
    // initialize
    $sel = `ls -sl`;
    if (`size $sel` != 1) {
        warning -sl 0 "listOfOrderedDeformers requires you to have one (1) object selected!";
        return {};
    }
    $selobj = $sel[0];
    $shapeList = `listRelatives -type shape`;
    if (`size $shapeList` < 1) {
        warning -sl 0 "listOfOrderedDeformers requires you to have one (1) object with a mesh selected!";
        return {};
    }

    // get shape name
    $shape = $shapeList[0];

    // get list of deformers for a the shape
    string $listOfDefs[];
    $globallistofdeformers = `ls -type geometryFilter`;
    for ($each in $globallistofdeformers) {
        $geo = `deformer -q -g $each`;
        for ($gtry in $geo) {
             if ($gtry == $shape) {
		        $listOfDefs[size($listOfDefs)] = $gtry;
             }
	    }
    }

    // check if there are deformers after all...
    if (`size $listOfDefs` < 1) {
        warning -sl 0 "listOfOrderedDeformers found no deformer on the object selected!";
        return {};
    }

    $lisofdefssize = `size $listOfDefs`;
    $listOfGroupIDs = `listConnections -d 0 -t "groupId" $shape`;

    // initialize return variable
    string $orderedDeformers[];
    $temp = `listConnections -c 0 -p 0 -s 1 -scn 1 -type geometryFilter ($shape+".inMesh")`;
    $orderedDeformers[0] = $temp[0];

    // loop and spider through each deformer to find which ones next
    for ($i = 1;$i<$lisofdefssize;$i++) {
        $listofgroups = `listConnections -d 0 -t "groupParts" $orderedDeformers[$i-1] `;
        if (`size $listofgroups`>0) {
            string $connected;
            for ($group in $listofgroups) {
                int $itDeforms = 0;
                while ($itDeforms < 1) {
                    $connectedTMP = `listConnections ($group+".inputGeometry")`;
                    $connected = $connectedTMP[0];
                    if (`stringArrayContains $connected $globallistofdeformers`) {
                        $itDeforms = 1;
                    } else {
                        $group = $connected;
                    }

                }
                $connectedGroupIDTMP = `listConnections ($group+".groupId")`;
                $connectedGroupID = $connectedGroupIDTMP[0];
                if (`stringArrayContains $connectedGroupID $listOfGroupIDs`) {
                    $orderedDeformers[$i] = $connected;
                }

            }
        } else {
            $connectedToInputGeometry = `listConnections  -type geometryFilter -d 0 ($orderedDeformers[$i-1]+".input[0].inputGeometry")`;
            $orderedDeformers[$i] = $connectedToInputGeometry[0];
        }
    }
    return $orderedDeformers;
}

// this will pop a gui that will help you reorder deformers
global proc int jd_reorderDeformersGUI () {
    if (`waitCursor -q -state` == 1) waitCursor -state 0;
    // initialize variables
    global int $jd_reorderDeformersScriptJobIndex;
    global string $jd_reorderDeformersGUI;
    $objsel = `ls -sl`;
    $obj = $objsel[0];

    // make sure you have something selected
    if (`size $objsel` >0) $shape = `listRelatives -s $obj`;

    // initialize window
    if (`window -exists $jd_reorderDeformersGUI`) deleteUI $jd_reorderDeformersGUI;
    $jd_reorderDeformersGUI = `window -t ("[JD] Reorder Deformer's on "+$obj)`;

    // list deformers on mesh
    $list = `jd_listOfOrderedDeformers`;
    $slist = `size $list`;
    if ($slist < 2) {
        print ("[JD]Reorder Deformer: Less than two deformers found on selected object: "+$obj+"\n");
    }
    // create numbered arrays for text labels and up and down buttons
    string $thisFrame[];
    string $thisForm[];
    string $textArray[];
    string $upButArray[];
    string $downButArray[];
    $hmargin = 5;
    $fmargin = 0;
    $butmargin = 1;

    if ($slist > 0) {
        // initialize form layout and its elements
        $form = `formLayout -numberOfDivisions ($slist)`;

        for ($i=0;$i<$slist;$i++) {
            //commands to assign
            string $upC, $downC;
            if ($i>0) $upC = ("reorderDeformers "+$list[$i]+" "+$list[$i-1]+" "+$shape[0]+" ; waitCursor -state 1; jd_reorderDeformer; ");
            if ($i<($slist-1)) $downC = ("reorderDeformers "+$list[$i+1]+" "+$list[$i]+" "+$shape[0]+" ;  waitCursor -state 1; jd_reorderDeformer; ");

            $thisFrame[$i] = `frameLayout -bv 0 -lv 0 -p $form `;
            $thisForm[$i] = `formLayout -p $thisFrame[$i] -numberOfDivisions 4`;
            $textArray[$i] = `text -p $thisForm[$i] -label (($i+1)+". "+$list[$i])`;
            $upButArray[$i] = `button -p $thisForm[$i] -label  "up" -c $upC`;
            $downButArray[$i] = `button -p $thisForm[$i] -label "down" -c $downC`;

            // turn off buttons that are on top or below everything
            if ($i == 0) button -e -l "" -en 0 $upButArray[$i];
            if ($i == ($slist-1)) button -e -l "" -en 0 $downButArray[$i];

            formLayout -e
                -attachForm     $downButArray[$i] "bottom" $hmargin
                -attachPosition $downButArray[$i] "top" $butmargin 2
                -attachOppositeForm  $downButArray[$i] "left" -50
                -attachForm     $downButArray[$i] "right" $hmargin

                -attachForm     $upButArray[$i] "top" $hmargin
                -attachPosition $upButArray[$i] "bottom" $butmargin 2
                -attachOppositeForm  $upButArray[$i] "left" -50
                -attachForm     $upButArray[$i] "right" $hmargin

                -attachForm     $textArray[$i] "top" $hmargin
                -attachForm     $textArray[$i] "bottom" $hmargin
                -attachForm     $textArray[$i] "left" $hmargin
                -attachControl  $textArray[$i] "right" $hmargin $upButArray[$i]

                $thisForm[$i];

        }

        formLayout -e
            -attachForm $thisFrame[0] "top" $fmargin
            -attachForm $thisFrame[0] "left" 0
            -attachForm $thisFrame[0] "right" 0
            -attachPosition $thisFrame[0] "bottom" $fmargin 1
            $form;

        for ($i=1;$i<$slist;$i++) {
                formLayout -e
                    -attachPosition $thisFrame[$i] "top" $fmargin ($i)
                    -attachForm $thisFrame[$i] "left" 0
                    -attachForm $thisFrame[$i] "right" 0
                    -attachPosition $thisFrame[$i] "bottom" $fmargin ($i+1)
                    $form;
        }
    } else {
        $closeCommand = ("deleteUI "+$jd_reorderDeformersGUI);
        $closeForm = `formLayout -p $jd_reorderDeformersGUI -numberOfDivisions 5`;
        $closeText = `text -w 350 -label "Must have at least one object with at least two deformers selected." -p $closeForm`;
        $closeButton = `button -w 350 -l "close" -p $closeForm -c $closeCommand`;
        formLayout -e
            -attachForm $closeText "top" 5
            -attachForm $closeText "left" 5
            -attachForm $closeText "right" 5

            -attachControl $closeButton "top" 5 $closeText
            -attachForm $closeButton "left" 5
            -attachForm $closeButton "right" 5
            -attachForm $closeButton "bottom" 5

            $closeForm;
    }
    showWindow $jd_reorderDeformersGUI;
    if ($slist == 0) {
        window -e -topLeftCorner 200 200 -h 100 -w 360 $jd_reorderDeformersGUI;
    } else {
        window -e -topLeftCorner 200 200 -w 1 -h (clamp(1,$slist,$slist) * 25) $jd_reorderDeformersGUI;
    }

    return 1;
}

global proc jd_reorderDeformer () {
    global int $jd_reorderDeformerScriptJobIndex;
    global int $jd_reorderDeformerScriptJobIndex2;
    global string $jd_reorderDeformersGUI;
    jd_reorderDeformersGUI;
    $jd_reorderDeformerScriptJobIndex = `scriptJob -p $jd_reorderDeformersGUI -runOnce 1 -e "SelectionChanged" "jd_reorderDeformer"`;
}

jd_reorderDeformer;

Posted on Oct 28, 2010

List Ordered Deformers

Since Maya 2011, there's a new (scripted) function 'findRelatedDeformer' that lists down all the deformers controlling a particular mesh. This is long overdue. And now it's finally here, it's not perfect. Deformers are listed in the order they were created (I think.). I wrote this wrapper script list out deformers for a geometry and also sort out the return list in the order of deformation for a particular object. Just to note, I'm still using the same 'findRelatedDeformer' function to let my iterator know when to stop. This is not necessary but until I've found another method, I'll keep this as is.

Update, this function is no longer relying on the 'findRelatedDeformer' for it to work. And I fixed it so that it will still return the correct nodes even though there were no 'groupParts' nodes used.

This function is useful if you want to replace the "List of all input operations..." dialog box in Maya that has become buggy ever since they've switched to using PyQt. I'm sure they'll quickly repair this, but til then people will need an alternative. I think I'll work on one.

I scripted this too.

// this procedure will return a list of deformers ordered
global proc string[] jd_listOfOrderedDeformers () {
    // initialize
    $sel = `ls -sl`;
    if (`size $sel` != 1) {
        warning -sl 0 "listOfOrderedDeformers requires you to have one (1) object selected!";
        return {};
    }
    $selobj = $sel[0];
    $shapeList = `listRelatives -type shape`;
    if (`size $shapeList` < 1) {
        warning -sl 0 "listOfOrderedDeformers requires you to have one (1) object with a mesh selected!";
        return {};
    }

    // get shape name
    $shape = $shapeList[0];

    // get list of deformers for a the shape
    string $listOfDefs[];
    $globallistofdeformers = `ls -type geometryFilter`;
    for ($each in $globallistofdeformers) {
        $geo = `deformer -q -g $each`;
        for ($gtry in $geo) {
             if ($gtry == $shape) {
		        $listOfDefs[size($listOfDefs)] = $gtry;
             }
	    }
    }

    // check if there are deformers after all...
    if (`size $listOfDefs` < 1) {
        warning -sl 0 "listOfOrderedDeformers found no deformer on the object selected!";
        return {};
    }

    $lisofdefssize = `size $listOfDefs`;
    $listOfGroupIDs = `listConnections -d 0 -t "groupId" $shape`;

    // initialize return variable
    string $orderedDeformers[];
    $temp = `listConnections -c 0 -p 0 -s 1 -scn 1 -type geometryFilter ($shape+".inMesh")`;
    $orderedDeformers[0] = $temp[0];

    // loop and spider through each deformer to find which ones next
    for ($i = 1;$i<$lisofdefssize;$i++) {
        $listofgroups = `listConnections -d 0 -t "groupParts" $orderedDeformers[$i-1] `;
        if (`size $listofgroups`>0) {
            string $connected;
            for ($group in $listofgroups) {
                int $itDeforms = 0;
                while ($itDeforms < 1) {
                    $connectedTMP = `listConnections ($group+".inputGeometry")`;
                    $connected = $connectedTMP[0];
                    if (`stringArrayContains $connected $globallistofdeformers`) {
                        $itDeforms = 1;
                    } else {
                        $group = $connected;
                    }

                }
                $connectedGroupIDTMP = `listConnections ($group+".groupId")`;
                $connectedGroupID = $connectedGroupIDTMP[0];
                if (`stringArrayContains $connectedGroupID $listOfGroupIDs`) {
                    $orderedDeformers[$i] = $connected;
                }

            }
        } else {
            $connectedToInputGeometry = `listConnections  -type geometryFilter -d 0 ($orderedDeformers[$i-1]+".input[0].inputGeometry")`;
            $orderedDeformers[$i] = $connectedToInputGeometry[0];
        }
    }
    return $orderedDeformers;
}
64 SQL queries have been executed to show this page