Exit
  • Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
  • 한국 커뮤니티
1

Sort / Order Selected Layers (Alphabetically)?

Explorer ,
Feb 14, 2018 Feb 14, 2018

Hi,

I'm looking for a script to order selected layers alphabetically. I'm familiar with  Adobe Photoshop Scripts | Trevor Morris Photographics​, but am looking for constraint to selection. I've tried using this script: get array of selected layers in photoshop via extendscript · GitHub in combination, however, I've hit a wall.

Thanks,

Tom

TOPICS
Actions and scripting
30.7K
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines

correct answers 1 Correct answer

People's Champ , Feb 15, 2018 Feb 15, 2018

I reproduced the error ).

This should work

var idx_shift = 0; 

try { activeDocument.backgroundLayer } catch (e) { idx_shift = 1; } 

while (1) 

    { 

    var list = get_selected_layers(); 

 

    if (!list) { alert("No selected layers"); break; } 

 

    var list2 = new Array(); 

    for (var i in list) list2.push(list); 

 

    function cmp(a, b)  

        { 

        var x = expand_numbers(a[0]); 

        var y = expand_numbers(b[0]); 

 

        if (x > y) return -1; 

        if (x < y) return 1; 

...
Translate
Adobe
People's Champ ,
Feb 15, 2018 Feb 15, 2018

Try this code )

while (1)

    {

    var list = get_selected_layers();

    if (!list) { alert("No selected layers"); break; }

    var list2 = new Array();

    for (var i in list) list2.push(list);

    function cmp(a, b)

        {

        var x = expand_numbers(a[0]);

        var y = expand_numbers(b[0]);

        if (x > y) return -1;

        if (x < y) return 1;

        return 0;

        }

    list.sort(cmp);

    var cont = false;

    for (var i = 0; i < list.length; i++)

        {

        if (list2[1] != list[1])

            {

            set_layers_index(list2[1], list[1]);

            cont = true;

            break;

            }

        }

    if (!cont) break;

    }

alert("Done!");

//////////////////////////////////////////////////////////////////

function set_layers_index(cur_idx, new_idx)

    {

    try {

        var d = new ActionDescriptor();

        var r1 = new ActionReference();

        r1.putIndex( charIDToTypeID( "Lyr " ), cur_idx);

        var r2 = new ActionReference();

        r2.putIndex( charIDToTypeID( "Lyr " ), new_idx );

        d.putReference( charIDToTypeID( "null" ), r1 );

        d.putReference( charIDToTypeID( "T   " ), r2 );

        executeAction( charIDToTypeID( "move" ), d, DialogModes.NO );

        }

    catch (e) { alert(e);  }

    }

//////////////////////////////////////////////////////////////////

function get_selected_layers()

    {

    try {

        var r = new ActionReference();   

        r.putProperty(charIDToTypeID("Prpr"), stringIDToTypeID("targetLayers"));  

        r.putEnumerated(charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt"));

        var list = executeActionGet(r).getList(stringIDToTypeID("targetLayers"));

        var n = 0;

        try { activeDocument.backgroundLayer } catch (e) { n = 1; }

        var len = list.count;

   

        var selected_layers = new Array();

   

        for (var i = 0; i < len; i++)

            {

            try

                {

                var idx = list.getReference(i).getIndex() + n;

                var r = new ActionReference();

                r.putProperty(charIDToTypeID("Prpr"), stringIDToTypeID("name"));  

                r.putIndex( charIDToTypeID( "Lyr " ), idx);

                var ret = executeActionGet(r).getString(stringIDToTypeID("name"));

                selected_layers.push([executeActionGet(r).getString(stringIDToTypeID("name")), idx]);

                }

            catch (e) { alert(e); return null; }

            }

   

        return selected_layers;

        }

    catch (e) { return null; }

    }

////////////////////////////////////////////////////////////////////////////////////////////

function expand_numbers(s, max_digit)

    {

    if (max_digit == undefined) max_digit = 10;   

    var digit_cnt;

    s = s.toString();

   

    var len = s.length;

    var s1 = "";

    for (var i = len-1; i >= 0; i--)

        {

        var c = s.charAt(i);

        if (c >= "0" && c <="9")

            {

            if (digit_cnt == undefined)    

                digit_cnt = 1;

            else                       

                ++digit_cnt;

            s1 += c;

            }

        else if (digit_cnt != undefined)

            {

            if (digit_cnt < max_digit) for (var n = 0; n < max_digit-digit_cnt; n++) s1 += "0";

            s1 += c;

            digit_cnt = undefined;

            }

        else

            {

            s1 += c;

            }

        }

    if (digit_cnt != undefined && digit_cnt < max_digit)

        for (var n = 0; n < max_digit-digit_cnt; n++) s1 += "0";

    len = s1.length;

    var ret = "";

    for (var i = len-1; i >= 0; i--) ret += s1.charAt(i);

    ret = ret.toUpperCase();

    return ret;

    }

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Feb 15, 2018 Feb 15, 2018

Thanks!

I ran the script and all but one of the selected layers got grouped into the group above them. I undid that and placed the group below all of the selected layers and ran again. Got a script alert: Error: General Photoshop error occurred. This functionality may not be available in this version of Photoshop.

- The command "Move" is not currently available.

I click OK or the x button and a new script alert appears (saying the same thing). I cannot exit Script Alerts...

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
People's Champ ,
Feb 15, 2018 Feb 15, 2018

Please post the screenshot of your layers structures and their selection. What version of Photoshop are you running?

upd. change

catch (e) { alert(e);  }

to

catch (e) { alert(e); throw(e);  }

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
People's Champ ,
Feb 15, 2018 Feb 15, 2018

I reproduced the error ).

This should work

var idx_shift = 0; 

try { activeDocument.backgroundLayer } catch (e) { idx_shift = 1; } 

while (1) 

    { 

    var list = get_selected_layers(); 

 

    if (!list) { alert("No selected layers"); break; } 

 

    var list2 = new Array(); 

    for (var i in list) list2.push(list); 

 

    function cmp(a, b)  

        { 

        var x = expand_numbers(a[0]); 

        var y = expand_numbers(b[0]); 

 

        if (x > y) return -1; 

        if (x < y) return 1; 

        return 0; 

        } 

 

    list.sort(cmp); 

    var cont = false; 

 

    for (var i = 0; i < list.length; i++) 

        { 

        if (list2[1] != list[1])  

            { 

            set_layers_index(list2[1], list[1]); 

            cont = true; 

            break; 

            } 

        } 

 

    if (!cont) break; 

    } 

 

alert("Done!"); 

 

////////////////////////////////////////////////////////////////// 

function set_layers_index(cur_idx, new_idx) 

    { 

    try { 

        var d = new ActionDescriptor(); 

 

        var r1 = new ActionReference(); 

        r1.putIndex( charIDToTypeID( "Lyr " ), cur_idx); 

 

        var r2 = new ActionReference(); 

        r2.putIndex( charIDToTypeID( "Lyr " ), new_idx-idx_shift ); 

 

        d.putReference( charIDToTypeID( "null" ), r1 ); 

        d.putReference( charIDToTypeID( "T   " ), r2 ); 

 

        executeAction( charIDToTypeID( "move" ), d, DialogModes.NO ); 

        } 

    catch (e) { alert(e); throw(e); } 

    } 

 

////////////////////////////////////////////////////////////////// 

function get_selected_layers() 

    { 

    try { 

        var r = new ActionReference();     

        r.putProperty(charIDToTypeID("Prpr"), stringIDToTypeID("targetLayers"));    

        r.putEnumerated(charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt")); 

 

        var list = executeActionGet(r).getList(stringIDToTypeID("targetLayers")); 

 

        var len = list.count; 

     

        var selected_layers = new Array(); 

     

        for (var i = 0; i < len; i++) 

            { 

            try  

                { 

                var idx = list.getReference(i).getIndex() + idx_shift; 

 

                var r = new ActionReference(); 

                r.putProperty(charIDToTypeID("Prpr"), stringIDToTypeID("name"));    

                r.putIndex( charIDToTypeID( "Lyr " ), idx); 

 

                var ret = executeActionGet(r).getString(stringIDToTypeID("name")); 

 

                selected_layers.push([executeActionGet(r).getString(stringIDToTypeID("name")), idx]); 

                } 

 

            catch (e) { alert(e); return null; } 

            } 

     

        return selected_layers; 

        } 

 

    catch (e) { return null; } 

    } 

 

//////////////////////////////////////////////////////////////////////////////////////////// 

function expand_numbers(s, max_digit) 

    { 

    if (max_digit == undefined) max_digit = 10;     

 

    var digit_cnt; 

 

    s = s.toString(); 

     

    var len = s.length; 

 

    var s1 = ""; 

 

    for (var i = len-1; i >= 0; i--)  

        { 

        var c = s.charAt(i); 

 

        if (c >= "0" && c <="9") 

            { 

            if (digit_cnt == undefined)      

                digit_cnt = 1; 

            else                         

                ++digit_cnt; 

 

            s1 += c; 

            } 

        else if (digit_cnt != undefined)  

            { 

            if (digit_cnt < max_digit) for (var n = 0; n < max_digit-digit_cnt; n++) s1 += "0"; 

 

            s1 += c; 

            digit_cnt = undefined; 

            } 

        else 

            { 

            s1 += c; 

            } 

        } 

 

    if (digit_cnt != undefined && digit_cnt < max_digit) 

        for (var n = 0; n < max_digit-digit_cnt; n++) s1 += "0"; 

 

    len = s1.length; 

 

    var ret = ""; 

 

    for (var i = len-1; i >= 0; i--) ret += s1.charAt(i); 

 

    ret = ret.toUpperCase(); 

 

    return ret; 

    } 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Feb 21, 2018 Feb 21, 2018

Amazing! Thank you very much--I really appreciate it.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Feb 26, 2018 Feb 26, 2018

I compared performance of our scripts and found the more selected layers the longer time your script needs to sort all of them. Only up to 10 selected layers yours is a little faster - here is comparision in seconds (layers number / yours / mine):

10     /     0.12     /     0.17

20     /     2.20     /     0.38

30     /     8.00     /     0.55

40     /     25.4     /     0.80

50     /     57.5     /     1.00

It also does not handle layers with same name like '1' and '1', 'Layer 0' and 'Layer 0' or 'a' and 'A'. It's looping endlessly itself...

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
People's Champ ,
Feb 26, 2018 Feb 26, 2018

Here is new version whithout "while" cycle )

var idx_shift = 0;   

try { activeDocument.backgroundLayer } catch (e) { idx_shift = 1; }   

var list = get_selected_layers();   

if (list)

    {

    var orig_idx = new Array();   

    for (var i in list) orig_idx.push(list[1]);   

    function cmp(a, b)    

        {   

        var x = expand_numbers(a[0]);   

        var y = expand_numbers(b[0]);   

        if (x > y) return -1;   

        if (x < y) return 1;   

        return 0;   

        }   

    list.sort(cmp);   

    for (var i = list.length-1; i >= 0; i--) set_layers_index(list[2], orig_idx);   

    }

alert("Done!");   

   

//////////////////////////////////////////////////////////////////   

function set_layers_index(id, idx)   

    {   

    try {   

        var d = new ActionDescriptor();   

   

        var r1 = new ActionReference();   

        r1.putIdentifier( charIDToTypeID( "Lyr " ), id);   

   

        var r2 = new ActionReference();   

        r2.putIndex( charIDToTypeID( "Lyr " ), idx-idx_shift );   

   

        d.putReference( charIDToTypeID( "null" ), r1 );   

        d.putReference( charIDToTypeID( "T   " ), r2 );   

   

        executeAction( charIDToTypeID( "move" ), d, DialogModes.NO );   

        }   

    catch (e) { alert(e); throw(e); }   

    }   

   

//////////////////////////////////////////////////////////////////   

function get_selected_layers()   

    {   

    try {   

        var r = new ActionReference();       

        r.putProperty(charIDToTypeID("Prpr"), stringIDToTypeID("targetLayers"));      

        r.putEnumerated(charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt"));   

   

        var list = executeActionGet(r).getList(stringIDToTypeID("targetLayers"));   

   

        var len = list.count;   

       

        var selected_layers = new Array();   

       

        for (var i = 0; i < len; i++)   

            {   

            try    

                {   

                var idx = list.getReference(i).getIndex() + idx_shift;   

   

                var r = new ActionReference();   

                r.putIndex( charIDToTypeID( "Lyr " ), idx);   

                var ret = executeActionGet(r);

   

                selected_layers.push([ret.getString(stringIDToTypeID("name")), idx, ret.getString(stringIDToTypeID("layerID"))]);   

                }   

   

            catch (e) { alert(e); return null; }   

            }   

       

        return selected_layers;   

        }   

   

    catch (e) { return null; }   

    }   

   

////////////////////////////////////////////////////////////////////////////////////////////   

function expand_numbers(s, max_digit)   

    {   

    if (max_digit == undefined) max_digit = 10;       

   

    var digit_cnt;   

   

    s = s.toString();   

       

    var len = s.length;   

   

    var s1 = "";   

   

    for (var i = len-1; i >= 0; i--)    

        {   

        var c = s.charAt(i);   

   

        if (c >= "0" && c <="9")   

            {   

            if (digit_cnt == undefined)        

                digit_cnt = 1;   

            else                           

                ++digit_cnt;   

   

            s1 += c;   

            }   

        else if (digit_cnt != undefined)    

            {   

            if (digit_cnt < max_digit) for (var n = 0; n < max_digit-digit_cnt; n++) s1 += "0";   

   

            s1 += c;   

            digit_cnt = undefined;   

            }   

        else   

            {   

            s1 += c;   

            }   

        }   

   

    if (digit_cnt != undefined && digit_cnt < max_digit)   

        for (var n = 0; n < max_digit-digit_cnt; n++) s1 += "0";   

   

    len = s1.length;   

   

    var ret = "";   

   

    for (var i = len-1; i >= 0; i--) ret += s1.charAt(i);   

   

    ret = ret.toUpperCase();   

   

    return ret;   

    }   

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Jul 26, 2018 Jul 26, 2018

btw now your script is twice faster than mine. Both are exremaly fast though, but yours does not regroup layers - it s why

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Sep 18, 2022 Sep 18, 2022

Hey there! 

A little late to the party but hopefully you see this. 

I am trying to use your script in PS 22.5.6

I receive error "

Illegal argument - Argument 2 - Numerical value expected.

Any ideas?

Thanks!

 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Feb 26, 2018 Feb 26, 2018

Before you run script go to 'Layers' panel, select 'Panel Oprions' from dropdown menu (you open clicking icon in right upper corner of panel), make 'Add "copy" to copied Layers and Groups' box empty. Script will be working if that won't be done, but all layer(Set)s get 'copy' word in their names. It is possible to remove it by script, but I did not do it as because of Photoshop bug there is need to select each single layer before renaming what increases time of performance. If you want script worked extremaly fast, press 'tab' key to toggle off your panels (it's scriptable but I let user decide of it). Script works for background and all kind of layers (those nasted in all levels groups as well). If any group will be selected before running script it is going to be unselected. Sorting is based on modified order of ASCII characters, so generally it is the same for digits and non letter characters. Difference is that order for letters is like: AaBbCc(...)Zz. Script distinguishes letters case and numbers in names - not as single digits but row of them - so there will be for ex. this order applied: 0, 1, 2, 3, 10, 99, 100 and so on. I didn't sort for any possible case there can happen but probably noone uses so complex layers names it ever was needed to cover unusual namings. It works also for layers having same content and length, while for example 'A' named layer will be sorted before 'a' named layer. I did not play with (disabled) linked layers, however those selected keep their links to each other while lose to those they were unselected and disabled ones gets enabled. These properties are possible to retrieve but as far there is no need to do it I didn't spend time for it. Visibility, effects and transparency stay untouched. It took 7,5 second with toggled off panels for 299 layer with background, so it gives 1 second for 40 layers! If you get some errors let me know so I'll make fixes.

gT = new Date().getTime(), $.level = 0; function sTT(v) {return stringIDToTypeID(v)}

function arr(v) {

     (ref1 = new ActionReference()).putProperty(sTT('property'), tL = sTT('targetLayers'))

     ref1.putEnumerated(sTT('document'), sTT('ordinal'), sTT('targetEnum'))

     if ((dsc1 = executeActionGet(ref1)).hasKey(tL)) {for(lst = dsc1.getList(tL), i = 0; i < lst.count;) {

          (ref2 = new ActionReference()).putIndex(sTT('layer'), lst.getReference(i++).getIndex() + bG), s = 'Start'

          if (typeIDToStringID((dsc = executeActionGet(ref2)).getEnumerationValue(sTT(lS = 'layerSection'))) == lS + s)

               {ref2.putIdentifier(sTT('layer'), dsc.getInteger(sTT('layerID'))), dsc1.putReference(sTT('null'), ref2)

               dsc1.putEnumerated(sTT(sM = 'selectionModifier'), sTT(sM + 'Type'), sTT('removeFromSelection'))

               dsc1.putBoolean(sTT('makeVisible'), false), executeAction(sTT('select'), dsc1, DialogModes.NO)}

          else v.unshift([dsc.getString(sTT('name')), dsc.getInteger(sTT('layerID'))])}

     }

     return v

}

(ref = new ActionReference()).putIdentifier(sTT('layer'), 1)

try{bG = !(dsc = executeActionGet(ref)).getBoolean

(sTT('background'))} catch (err) {bG = 1}

if ((sL = arr([])).length > 1) {

     (srt = Array().slice.call(sL)).sort(function(v1, v2) {

          function l(v) {return v.length}; if ((v1 = v1[0]) != v2 = v2[0]) {

               for(g = 0; g < l(v1); g++) {

                    if ((v1g = v1) != v2g = v2) {

                         function dig(v) {return !isNaN(v)}

                         if (dig(v1g) && dig(v2g)) {

                              function slc(v) {

                                   return +String(v).slice(g).match(/\d+/)

                              }

                              return slc(v1) - slc(v2)

                         }

                         function cCA(v) {

                              return v.charCodeAt() -

                              (/[a-z]/.test(v) ? 31.5 : 0)

                         }

                         if (v1g && v2g) return cCA(v1g) - cCA(v2g)

                    }

                    if (!v1g || !v2g) return l(v1) - l(v2)

               }

          }

     });

     (ref1 = new ActionReference()).putEnumerated(sTT('layer'), sTT('ordinal'),

     sTT('targetEnum')); (dsc1 = new ActionDescriptor()).putReference(sTT('null'), ref1)

     dsc1.putInteger(sTT('version'), 5), executeAction(sTT('duplicate'), dsc1, DialogModes.NO);

     dL = arr([]);

     (ref1 = new ActionReference()).putClass(sTT('layerSection'));

     (dsc1 = new ActionDescriptor()).putReference(sTT('null'), ref1);

     (ref2 = new ActionReference()).putEnumerated(sTT('layer'),

     sTT('ordinal'), sTT('targetEnum')), dsc1.putReference(sTT

     ('from'), ref2), executeAction(sTT('make'), dsc1, DialogModes.NO)

     grp = executeActionGet(ref2).getInteger(sTT('layerID' ))

     function del(v1, v2) {

          eval("(ref1 = new ActionReference()).put" + v1 + "(sTT('layer'), v2)");

          (dsc1 = new ActionDescriptor()).putReference(sTT('null'), ref1)

          executeAction(sTT('delete'), dsc1, DialogModes.NO)

     }

     for(i = 0; i < sL.length; i++) {

          for(j = 0; j < srt.length; j++) {

               if (sL[1] == srt[1]) {

                    (ref1 = new ActionReference()).putIdentifier(sTT('layer'), dL.shift()[1]);

                    (dsc1 = new ActionDescriptor()).putReference(sTT('null'), ref1);

                    (ref1 = new ActionReference()).putIdentifier(sTT('layer'), sL[1])

                    t = executeActionGet(ref1).getInteger(sTT('itemIndex'));

                    (ref2 = new ActionReference()).putIndex(sTT('layer'), t)

                    dsc1.putReference(sTT('to'), ref2), executeAction

                    (sTT('move'), dsc1, DialogModes.NO);

                    del('Index', t - (bG ? 0 : 1))

                    if (!bG && t == 1) {

                         (ref1 = new ActionReference()).putClass(sTT('backgroundLayer'));

                         (dsc1 = new ActionDescriptor()).putReference(sTT('null'), ref1);

                         (ref2 = new ActionReference()).putIndex(sTT('layer'), t);

                         dsc1.putReference(sTT('using'), ref2), executeAction

                         (sTT('make'), dsc1, DialogModes.NO)

                    }

                    break

               }

          }

     }

     del('Identifier', grp), new Date().getTime() - gT

}

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Feb 09, 2021 Feb 09, 2021

This dosnt work for me.. i simple her an error: 

https://www.dropbox.com/s/2rhkl0hmlo8wdpm/Screenshot%202021-02-09%20at%2009.56.23.png?dl=0

- Numerical value expected.

Line:75 

it seems to be erroring in the try-catch phase? Note that my document does not have a background layer.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Feb 09, 2021 Feb 09, 2021

You mean the code of r-bin (that contains try..catch statement) or mine you updated of?

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Feb 10, 2021 Feb 10, 2021

Yes sorry, the answer posted by r-bin above was throwing the error.  I found an alternative script on Github that worked instead in the end. 

 

var layers = activeDocument.layers;
    var layersArray = [];
    var len = layers.length;
    


    // store all layers in an array
    for (var i = 0; i < len; i++) {
        layersArray.push(layers[i]);
    }

    // sort layer top to bottom
    layersArray.sort();

    for (i = 0; i < len; i++) {
        layersArray[i].move(layers[i], ElementPlacement.PLACEBEFORE);
    }

 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Contributor ,
Jul 09, 2022 Jul 09, 2022

Hi,

As I'm a bit of a newbie, it would be great if you could post what the script in the end looked like (I'm not entirely sure how you combined the two scripts you mentioned) 🙂

Best,
Christina

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
Oct 29, 2022 Oct 29, 2022

Same question as Chris201Chris above is asking,

 

Many Thanks to Members who take the time to respond to Complex Questions.

especially when it is difficult to put into words Apstract ideas.

 

My question ! ? :

I am quite good with Photoshop, but when it comes to Coding / Scripts,

i am completely in the dark, 

and a simple way of Sorting Text Layers Alphabetically is what i need.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jun 28, 2024 Jun 28, 2024
LATEST
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines