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

Script for collecting files for a printing house

Engaged ,
Apr 26, 2018 Apr 26, 2018

Copy link to clipboard

Copied

Hello community,

if you are working together with printing houses and create files in AI that will sooner or later be printed there you might know that they need some more files than you actual AI file. In my case these usually are:

- your AI file

- your AI file with outlined fonts (in case they use a different OS and can't use your fonts)

- a printable PDF (PDF/X normally preferred)

- a preview PDF for administrative use

- any linked image

- the fonts used in your file

By the time I had to collect  these files mentioned above 3-4 times a day for different design files. So I thought it would be the right time for some automation. Searching the web I found a lot of code snippets I could use for this complex script so the origin is not totally mine.

What that script does is

- cleaning up your file by deleting not used colors, hidden layers, and hidden objects

- generating a newe folder on your desktop

- saving all files and formats as mentioned above in this folder ...

... except the fonts.

#target Illustrator

// GLOBAL

app.userInteractionLevel = UserInteractionLevel.DONTDISPLAYALERTS;

var scptver = "_MH_gather_printer_files_E / Mai 2018";

var typosafe = "mod_typo"; // Layers not to be deleted

var varnish = "varnish"; // Layer containing printing form for varnish

var white = "white"; // Layer containing printing form for white in case you print on transparent material

var printfolder = "_PRINT"; // Suffix used for the folder where all files for the printer are collected

var imagefolder = "images"; // sub-folder for images

var pdfOption = 'PDFX3-Setting'; // Name of your PDF setting for printable PDF

var pdfOption2 = 'lowResPDF-Setting'; // Name of your PDF settings für preview only PDF

var aiSuff = '_cs6.ai'; // Suffix attached to the open AI file determining the version

var aiSuff2 = '_cs6outl.ai'; // Suffix attached to the open AI file with outlined fonts determining the version

var pdfSuff = '_x3.pdf'; // Suffix attached to the printable PDF

var pdfSuff2 = '_lowres.pdf'; // Suffix attached to the preview PDF

var doc = app.activeDocument;

var original_file = doc.fullName;

var statuswin = new Window ('palette', "Collecting printer's files", [700, 200, 1100, 535], {independent:true});

// __________________________________________________________________________ //

// Define all names

var arr = doc.name.split(".");

var extension = "";

if (arr.length>1) extension = "." + arr.pop();

var filename = arr.join("."); // base file name for all further steps

var foldername = filename; // defining the first part of name of the folder where all files for the printer are collected

    foldername = foldername.replace(/RZ_/,""); // delete RZ_ in filename

    foldername = foldername.replace(/\s/g,"_"); // replace Blanks with _

    foldername = foldername.replace("ß","ss"); // replace ß with ss

    foldername = foldername.replace("%","Pr"); // replace % with Pr

    foldername = foldername.replace(/[^-a-zA-Z0-9._]/g,""); // discard all remaining special characters

var export_folder = "~/Desktop/" + foldername + printfolder; // name and place to save the folder

var assets_folder = new Folder (export_folder + "/" + imagefolder); // name and place for the sub-folder

var name_ai = filename + aiSuff;

var name_aizw = filename + aiSuff2;

var name_pdfprint = filename + pdfSuff;

var name_pdfpreview = filename + pdfSuff2;

var name_infofile = "_info_" + filename + ".txt";

// __________________________________________________________________________ //

// FUNCTIONS

// delete hidden objects

function delete_hidden () {

    var idoc = app.activeDocument; 

    for (i = idoc.pageItems.length-1; i >= 0; i--){ 

          if (idoc.pageItems.hidden == true){ 

               if (idoc.pageItems.name != typosafe) {

                idoc.pageItems.remove()}

               } 

            } 

}

// delete hidden layers

function delete_hidden_layers () {

    var myDoc = app.activeDocument;

    var layerCount = myDoc.layers.length;

        for (var ii = layerCount - 1; ii >= 0; ii--) {

        var currentLayer = myDoc.layers[ii];

            currentLayer.locked = false;

        var subCount = currentLayer.layers.length;

        for (var ss = subCount -1; ss >= 0; ss--){

        var subLayer = currentLayer.layers[ss];

        subLayer.locked = false;

        if (subLayer.visible == false){

            subLayer.visible = true;

            if (subLayer.name != typosafe) {

                subLayer.remove()}

            else {

                subLayer.visible = false};

            }

        }

    if (currentLayer.visible == false){

        currentLayer.visible = true;

         if (currentLayer.name != typosafe) {

                currentLayer.remove()}

            else {

                currentLayer.visible = false};

        }

    }

}

// hide layer containing varnish

function hide_lack () {

    var docwht = app.activeDocument; 

    var myLayers1 = docwht.layers; 

    var HideName1 = varnish; 

    try { 

        HideLayer1 = myLayers1.getByName (HideName1); 

        HideLayer1.visible = false; 

        redraw(); 

        } 

    catch (e) {} 

}

// hide layer containing white color

function hide_sfweiss () {

    var docwht = app.activeDocument; 

    var myLayers1 = docwht.layers; 

    var HideName1 = white; 

    try { 

        HideLayer1 = myLayers1.getByName (HideName1); 

        HideLayer1.visible = false; 

        redraw(); 

        } 

    catch (e) {} 

}

// outline all fonts

function fontvect (){

         var doc = app.activeDocument;

         while (doc.textFrames.length != 0) {

               doc.textFrames[0].createOutline();

               }

}

// load XMP Library

function loadXMPLibrary() { 

         if (!ExternalObject.AdobeXMPScript) { 

            try { 

                ExternalObject.AdobeXMPScript = new ExternalObject('lib:AdobeXMPScript'); 

            } catch (e) { 

              alert('Unable to load the AdobeXMPScript library!'); 

              return false; 

            } 

        } 

        return true; 

// unload XMP Library

function unloadXMPLibrary() { 

         if (ExternalObject.AdobeXMPScript) { 

            try { 

                ExternalObject.AdobeXMPScript.unload(); 

                ExternalObject.AdobeXMPScript = undefined; 

            } catch (e) { 

              alert('Unable to unload the AdobeXMPScript library!'); 

            } 

        } 

// list all used fonts in the document

function list_fonts () {

         var doc = app.activeDocument;

         var fontsInfo = []; 

         loadXMPLibrary (); 

         fontsInfo.push (getFontsInfo (doc.fullName)); 

         unloadXMPLibrary (); 

         var info = fontsInfo.join ('\n\n');

         return info;

}

// search for all used fonts in the document with ful info

function getFontsInfo(file) {

        var arr = [], 

            xmpFile,

            oXmp,

            fontNumber,

            i,

            path,

            fontname,

            fonttype,

            ns = 'http://ns.adobe.com/xap/1.0/t/pg/'; 

        xmpFile = new XMPFile(file.fsName, XMPConst.UNKNOWN, XMPConst.OPEN_FOR_READ); 

        oXmp = xmpFile.getXMP();  

        fontNumber = oXmp.countArrayItems(ns, 'xmpTPg:Fonts'); 

        xmpFile.closeFile(XMPConst.CLOSE_UPDATE_SAFELY); 

        if (fontNumber) {  

            for (i = 1; i <= fontNumber; i++) { 

                path = XMPUtils.composeArrayItemPath(ns, 'xmpTPg:Fonts', i); 

                fontname = oXmp.getStructField(ns, path, XMPConst.TYPE_FONT, 'fontName'); 

                fonttype = oXmp.getStructField(ns, path, XMPConst.TYPE_FONT, 'fontType'); 

                arr.push([fontname, ' \t(', fonttype, ')'].join('')); 

            } 

        } 

        return arr.join('\n'); 

}

// generate .txt file with info about collected files, fonts used in the doc, and images

function create_info (listImages) {

        listImages = unique(listImages);

        var doc = app.activeDocument; 

        var d = new Date ();

        var ddyear = d.getYear();

            ddyear += 1900;

        var ddmonth = d.getMonth();

        var ddday = d.getDate();

        var ddhour = d.getHours();

        var ddmin = d.getMinutes();

        if (ddmin < 10) {ddmin = "0"+ddmin};

        var Loginfo = new File (export_folder + '/' + name_infofile); 

            Loginfo.open ('w', 'TEXT', '????');

        var info = "This .zip file contains \n\n" +

                   name_ai + "\n" +

                   "< editable AI CS6 file > \n\n" +

                   name_aizw + "\n" +

                   "< editable AI CS6 file with outlined fonts> \n\n" +

                   name_pdfprint + "\n" +

                   "< printable PDF/X > \n\n" +

                   name_pdfpreview + "\n" +

                   "< preview PDF, not for printing >" +

                   "\n\n\n___________________________________________________________________________\n" +

                   "Placed images \n\n" +

                   listImages.join('\n') +

                   "\n\n\n___________________________________________________________________________\n" +

                   "Fonts used \n\n" +

                   list_fonts() +

                   "\n\n\n___________________________________________________________________________\n" +

                   "Colors used in document (not printing colors) \n\n" +

                   usedSwatches () +

                   "\n\n\n___________________________________________________________________________\n" +

                   "Files collected on \n" +

                   "\n" +

                   ddday +"."+ ddmonth +"."+ ddyear +", " + ddhour +":"+ ddmin +

                   "\n\n" + scptver;

              info = info.replace (/%20/g, " ");

            Loginfo.write(info); 

            Loginfo.close();

            }

           

// collect images linked in the document in sub-folder

function collect_images () {

    var doc = app.activeDocument;

    var listImages = [];

    var listImageFiles = [];

    var i, in_file, out_file;

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

        in_file = doc.placedItems.file;

        listImages.push (in_file.name);

        listImageFiles.push (in_file);

        listImages = unique (listImages);

        listImageFiles = unique(listImageFiles);

        }

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

        if (doc.rasterItems.embedded) continue;

        in_file = doc.rasterItems.file;

        listImages.push (in_file.name);

        listImageFiles.push (in_file);

        listImages = unique (listImages);

        listImageFiles = unique(listImageFiles);

        }

    var ii;

    var in_file_name;

    var howManyImages = listImageFiles.length;

    for (ii = 0; ii < listImageFiles.length; ii++) {

        in_file = listImageFiles[ii];

        in_file_name = listImages[ii];

        out_file = File(assets_folder + "/" + in_file_name);

        in_file.copy(out_file);

        }

    create_info (listImages);

}

// search array and delete double entries

function unique(ain) {  

         var seen = {}  

         var aout = []  

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

             var elt = ain  

             if (!seen[elt]) {  

                aout.push(elt)  

                seen[elt] = true  

                }  

             }  

          return aout

}

// save file as AI and return to base file

function saveCopyAsAI (nameAI) {

    var doc = app.activeDocument;

    var packaged_file = null;

        packaged_file = File (export_folder + "/" + nameAI);

    var save_options = new IllustratorSaveOptions();

        save_options.embedICCProfile = false;

        save_options.pdfCompatible = false

    doc.saveAs (packaged_file, save_options);

    doc.close ();

    app.open (File (original_file));

}

// save file as PDF and return to base file

function saveCopyAsPDF (setPDF, namePDF) {

        var doc = app.activeDocument;

        var destFolder = null;

            destFolder = export_folder;

        var options = null;   

            options = new PDFSaveOptions ();

            options.pDFPreset = setPDF;

            options.viewAfterSaving = false;

        var targetFile = null;

            targetFile = new File (destFolder + "/" + namePDF);   

        doc.saveAs (targetFile, options);

        doc.close ();

        app.open (File (original_file));

}

// list used swatches

function usedSwatches () {

    var docRef = app.activeDocument;

    var sInks = "";

    var iLength = activeDocument.inkList.length;

    for (var i = 0; i < iLength; i++) {

        sInks += docRef.inkList.name;

        sInks += "\n";

        }

    return (sInks);

}

// delete unused swatches

function DeleteUnusedSwatches () {

    if (app.documents.length = 0) {return;}

        var ActionSet = "QwertyflyScriptedActions" 

        var Action1Name = "KillSwatches" 

        var ActionString = '/version 3\n/name [ 24\n'+ Hexit(ActionSet) +'\n]\n/isOpen 0\n/actionCount 1\n/action-1 {\n/name [ 12\n'+ Hexit(Action1Name) +'\n]\n/keyIndex 0\n/colorIndex 0\n/isOpen 0\n/eventCount 2\n/event-1 {\n/useRulersIn1stQuadrant 1\n/internalName (ai_plugin_swatches)\n/localizedName [ 8\n5377617463686573\n]\n/isOpen 0\n/isOn 1\n/hasDialog 0\n/parameterCount 1\n/parameter-1 {\n/key 1835363957\n/showInPalette 1\n/type (enumerated)\n/name [ 17\n53656c65637420416c6c20556e75736564\n]\n/value 11\n}\n}\n/event-2 {\n/useRulersIn1stQuadrant 1\n/internalName (ai_plugin_swatches)\n/localizedName [ 8\n5377617463686573\n]\n/isOpen 0\n/isOn 1\n/hasDialog 1\n/showDialog 0\n/parameterCount 1\n/parameter-1 {\n/key 1835363957\n/showInPalette 1\n/type (enumerated)\n/name [ 13\n44656c65746520537761746368\n]\n/value 3\n}\n}\n}'; 

        createAction(ActionString,ActionSet);    

        ActionString = null;   

        app.doScript(Action1Name, ActionSet, false);   

        app.unloadAction(ActionSet,"");   

}

function createAction (str,act) {

    var f = new File('~/' + act+ '.aia');

    f.open('w');    

    f.write(str);    

    f.close();    

    app.loadAction(f);    

    f.remove();    

function Hexit(str) {

    var hex = '';

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

        hex += ''+str.charCodeAt(i).toString(16);

        }

    return hex;

// __________________________________________________________________________ //

// MAIN

function main () {

    if (app.documents.length > 1) {

        Window.alert ("Error! \nPlease make sure to have opened \nonly 1 document.");

    }   

    else {

        stwin ();

        delete_hidden_layers ();

        delete_hidden ();

        DeleteUnusedSwatches();

        stwin_delhidden ();

        if (!doc.saved) doc.save();

        if (assets_folder.exists || assets_folder.create());

        stwin_printfolder ();

        stwin_imagefolder ();

        collect_images ();

        stwin_images ();

        saveCopyAsAI (name_ai);

        stwin_cs6 ();

        saveCopyAsPDF (pdfOption, name_pdfprint);

        stwin_x3 ();

        fontvect ();

        stwin_fontvect ();

        hide_sfweiss ();

        stwin_sfweiss ();

        hide_lack ();

        stwin_lack ();

        saveCopyAsPDF (pdfOption2, name_pdfpreview);

        stwin_lowres ();

        fontvect ();

        saveCopyAsAI (name_aizw);

        stwin_cs6zw ();

        stwin_ende ();

        statuswin.close ();

        app.beep (); $.sleep(200); app.beep (); $.sleep(200); app.beep ();   

        Window.alert ("All files for printing house collected. \nRemember to add used fonts.");

        }

}

// __________________________________________________________________________ //

//START

var weiter = confirm ('COLLECT PRINTERS FILES: \n'+

                      '1. all hidden layers will be deleted \n'+

                      '2. all hidden objects will be deleted \n'+

                      '3. all colors not in use will be deleted \n'+

                      'after that the cleaned up file wil be saved.\n'+

                      'Images linked in this file will be collected.\n\n'+

                      'Naming conventions: \n'+

                      'varnish = layer for spot color varnish \n'+

                      'white = layer for spot color white \n\n'+

                      'Modified typo with effects attached to it \n'+

                      'should be duplicated and outlined in advance. \n\n'+

                      'To preserve the original typo from being deleted \n' +

                      'rename the layer containing the typo to mod_typo! \n\n'+

                      'Please make sure only 1 AI file is open! \n\n'+

                      'Go ahead?',"Hinweis");

if (weiter != true) {

    Window.alert ("Script cancelled. No changes have been made.")

    }

else {

    main ();

    };

                               

// __________________________________________________________________________ //

//STATUS WINDOW

function stwin () {

    statuswin.add ('panel',[15, 15, 385, 220], "Tasks:");

    statuswin.add ('statictext',[30, 30, 285, 100], "clean up an save base file ...");

    statuswin.add ('statictext',[30, 45, 285, 100], "generate folder for collected files ...");

    statuswin.add ('statictext',[30, 60, 285, 100], "generate sub-folder for images ...");

    statuswin.add ('statictext',[30, 75, 285, 100], "collect images ...");

    statuswin.add ('statictext',[30, 90, 285, 100], "save AI file ...");

    statuswin.add ('statictext',[30, 105, 285, 100], "save printable PDF ...");

    statuswin.add ('statictext',[30, 120, 285, 100], "outline fonts ...");

    statuswin.add ('statictext',[30, 135, 285, 100], "hide layer containing white ...");

    statuswin.add ('statictext',[30, 150, 285, 100], "hide layer containing varnish ...");

    statuswin.add ('statictext',[30, 165, 285, 100], "save preview-only PDF ...");

    statuswin.add ('statictext',[30, 180, 285, 100], "save AI file with outlined fonts...");

    statuswin.add ('statictext',[30, 195, 285, 100], "collect used fonts ...");

    statuswin.pnl = statuswin.add("panel", [15, 215, 385, 300], "Files collected ..."); 

    statuswin.pnl.progBar = statuswin.pnl.add("progressbar", [20, 30, 340, 50], 0, 100); 

    statuswin.pnl.progBarLabel = statuswin.pnl.add("statictext", [30, 33, 285, 235], "0%"); 

    statuswin.add ('statictext',[15, 310, 285, 400], scptver);

    statuswin.show ();

    }

function stwin_delhidden() {

statuswin.add ('statictext',[305, 30, 345, 100], "done");

statuswin.update();

statuswin.pnl.progBar.value= 10;  

statuswin.pnl.progBarLabel.text = statuswin.pnl.progBar.value+"%"; 

statuswin.update();

}

function stwin_printfolder() {

statuswin.add ('statictext',[305, 45, 345, 100], "done");

statuswin.update();

statuswin.pnl.progBar.value= 15;  

statuswin.pnl.progBarLabel.text = statuswin.pnl.progBar.value+"%"; 

statuswin.update();

}

function stwin_imagefolder() {

statuswin.add ('statictext',[305, 60, 345, 100], "done");

statuswin.update();

statuswin.pnl.progBar.value= 20;  

statuswin.pnl.progBarLabel.text = statuswin.pnl.progBar.value+"%"; 

statuswin.update();

}

function stwin_images() {

statuswin.add ('statictext',[305, 75, 345, 100], "done");

statuswin.update();

statuswin.pnl.progBar.value= 30;  

statuswin.pnl.progBarLabel.text = statuswin.pnl.progBar.value+"%"; 

statuswin.update();

}

function stwin_cs6() {

statuswin.add ('statictext',[305, 90, 345, 100], "done");

statuswin.update();

statuswin.pnl.progBar.value= 40;  

statuswin.pnl.progBarLabel.text = statuswin.pnl.progBar.value+"%"; 

statuswin.update();

}

function stwin_x3() {

statuswin.add ('statictext',[305, 105, 345, 100], "done");

statuswin.update();

statuswin.pnl.progBar.value= 50;  

statuswin.pnl.progBarLabel.text = statuswin.pnl.progBar.value+"%"; 

statuswin.update();

}

function stwin_fontvect() {

statuswin.add ('statictext',[305, 120, 345, 100], "done");

statuswin.update();

statuswin.pnl.progBar.value= 55;  

statuswin.pnl.progBarLabel.text = statuswin.pnl.progBar.value+"%"; 

statuswin.update();

}

function stwin_sfweiss() {

statuswin.add ('statictext',[305, 135, 345, 100], "done");

statuswin.update();

statuswin.pnl.progBar.value= 65;  

statuswin.pnl.progBarLabel.text = statuswin.pnl.progBar.value+"%"; 

statuswin.update();

}

function stwin_lack() {

statuswin.add ('statictext',[305, 150, 345, 100], "done");

statuswin.update();

statuswin.pnl.progBar.value= 70;  

statuswin.pnl.progBarLabel.text = statuswin.pnl.progBar.value+"%"; 

statuswin.update();

}

function stwin_lowres() {

statuswin.add ('statictext',[305, 165, 345, 100], "done");

statuswin.update();

statuswin.pnl.progBar.value= 80;  

statuswin.pnl.progBarLabel.text = statuswin.pnl.progBar.value+"%"; 

statuswin.update();

}

function stwin_cs6zw () {

statuswin.add ('statictext',[305, 180, 345, 100], "done");

statuswin.update();

statuswin.pnl.progBar.value= 90;  

statuswin.pnl.progBarLabel.text = statuswin.pnl.progBar.value+"%"; 

statuswin.update();

}

function stwin_ende() {

statuswin.add ('statictext',[305, 195, 345, 100], "to do");

statuswin.update();

statuswin.pnl.progBar.value= 100;  

statuswin.pnl.progBarLabel.text = statuswin.pnl.progBar.value+"%"; 

statuswin.update();

$.sleep(2000);

}

TOPICS
Scripting

Views

1.9K

Translate

Translate

Report

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
Adobe
Community Beginner ,
May 01, 2018 May 01, 2018

Copy link to clipboard

Copied

I ran the script, but ran into a few things:

• Errors out with this message:

Screen Shot 2018-05-01 at 3.09.19 PM.png

• I got a folder output with: a text file, one '_cs6.ai' file, and an 'images' folder with images in it, but it doesn't seem to have created the pdfs, the outlined version of the AI file, or the fonts (though wasn't sure if it was even supposed to output that based on your description).

Also, the task box shows text a bit jumbled (not important, but didn't look right):

Screen Shot 2018-05-01 at 3.00.56 PM.png

Votes

Translate

Translate

Report

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
Engaged ,
May 01, 2018 May 01, 2018

Copy link to clipboard

Copied

Hello, and thanks for testing and reply.

Please make sure that you have changed line 14 and 15. Yu have to put in the exact names of your PDF settings for printable PDF and preview-only PDF.

The problem with the status window seems to be a different OS: I did the script on a Mac (10.6.8). If you're using Windows you may even have to fix some others parts of the script.

Votes

Translate

Translate

Report

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 ,
May 02, 2018 May 02, 2018

Copy link to clipboard

Copied

I'm on a macOS as well (10.12.6).

Thanks for the help, got it to work by typing in the exact name of the PDF settings in the PDF dropdown menu (needs to include the [ ] brackets as well). So the PDF/X options had to be put in as '[PDF/X-4:2008]'.

The only other thing I noticed is that it doesn't output any of the 'Fonts used' in the .txt file. Not super big, but a little odd that it's even listed.

Votes

Translate

Translate

Report

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
Engaged ,
May 02, 2018 May 02, 2018

Copy link to clipboard

Copied

I'm working on it. The problem is that I have some snippets of code that enable AI to gather the font files via BridgeTalk and InDesign but when copying (old) Type 1 fonts it will result in 0 byte files. TrueType and OpenType fonts are gathered without a problem.

Votes

Translate

Translate

Report

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 ,
Jan 14, 2019 Jan 14, 2019

Copy link to clipboard

Copied

Hey! THANK YOU for this script. This does literally everything I need it to do, except for package my fonts. I was wondering if you were able to solve this issue?

Amazing script so far!

Votes

Translate

Translate

Report

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
Engaged ,
Jan 15, 2019 Jan 15, 2019

Copy link to clipboard

Copied

I'm very sorry - no! As we are only working with Extensis Font Server I can only test scripts for collectin fonts on my own Mac. And as mentioned above the snippets of code I found so far have problems with collectin some type of fonts.

Votes

Translate

Translate

Report

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 ,
Jan 16, 2019 Jan 16, 2019

Copy link to clipboard

Copied

Alrighty! Well I'm going to work on the code as well, if I get anywhere with the collection of fonts I will let you know. Again this script saves a ton of time on my end. Thank you q3! You're a rockstar.

Votes

Translate

Translate

Report

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 ,
Jan 18, 2019 Jan 18, 2019

Copy link to clipboard

Copied

Hey q3player,

I have another curious question. Is there a way to get the script to run so that is saves the documents in the current location of the file, rather than on your desktop?

I'm working on a server, and would love to be able to point to the documents current folder, rather than my desktop.

Just trying to streamline the process a little.

Votes

Translate

Translate

Report

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
Engaged ,
Jan 22, 2019 Jan 22, 2019

Copy link to clipboard

Copied

As the script is supposed to clean up your original AI file e.g. delete hidden layers and as far as there are some problems when saving on a server volume I haven't even thought about that option.

Votes

Translate

Translate

Report

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 01, 2019 Feb 01, 2019

Copy link to clipboard

Copied

LATEST

Hey q3player​, I figured out the font issue, and also edited the script so you can select the destination you want the folder to be created in. I figured I'd share it with you, since you did 95% of the work on it! Check it out, and let me know if it packages up your fonts for you. !

// GLOBAL 

 

app.userInteractionLevel = UserInteractionLevel.DONTDISPLAYALERTS; 

 

var scptver = "_MH_gather_printer_files_E / Mai 2018"; 

 

var typosafe = "mod_typo"; // Layers not to be deleted 

var varnish = "varnish"; // Layer containing printing form for varnish 

var white = "white"; // Layer containing printing form for white in case you print on transparent material 

var printfolder = "_Release"; // Suffix used for the folder where all files for the printer are collected 

var imagefolder = "Links"; // sub-folder for images 

var pdfOption = '[High Quality Print]'; // Name of your PDF setting for printable PDF 

var pdfOption2 = '[Smallest File Size]'; // Name of your PDF settings für preview only PDF 

var aiSuff = '_.ai'; // Suffix attached to the open AI file determining the version 

var aiSuff2 = '_OL.ai'; // Suffix attached to the open AI file with outlined fonts determining the version 

var pdfSuff = '_HR.pdf'; // Suffix attached to the printable PDF 

var pdfSuff2 = '_LR.pdf'; // Suffix attached to the preview PDF 

 

var doc = app.activeDocument; 

var original_file = doc.fullName; 

 

var statuswin = new Window ('palette', "Collecting printer's files", [700, 200, 1100, 535], {independent:true}); 

 

// __________________________________________________________________________ // 

// Define all names 

 

var arr = doc.name.split("."); 

var extension = ""; 

if (arr.length>1) extension = "." + arr.pop(); 

var filename = arr.join("."); // base file name for all further steps 

var foldername = filename; // defining the first part of name of the folder where all files for the printer are collected 

    foldername = foldername.replace(/RZ_/,""); // delete RZ_ in filename 

    foldername = foldername.replace(/\s/g,"_"); // replace Blanks with _ 

    foldername = foldername.replace("ß","ss"); // replace ß with ss 

    foldername = foldername.replace("%","Pr"); // replace % with Pr 

    foldername = foldername.replace(/[^-a-zA-Z0-9._]/g,""); // discard all remaining special characters 

var destFolder = app.activeDocument.path.selectDlg('Select the location where you want to save the files.'); // name and place to save the folder

var export_folder = new Folder (foldername + printfolder);

var assets_folder = new Folder (destFolder + export_folder + "/" + imagefolder); // name and place for the sub-folder 

var name_ai = filename + aiSuff; 

var name_aizw = filename + aiSuff2; 

var name_pdfprint = filename + pdfSuff; 

var name_pdfpreview = filename + pdfSuff2; 

var name_infofile = "_info_" + filename + ".txt"; 

 

// __________________________________________________________________________ // 

// FUNCTIONS 

 

// delete hidden objects 

function delete_hidden () { 

    var idoc = app.activeDocument;   

    for (i = idoc.pageItems.length-1; i >= 0; i--){   

          if (idoc.pageItems.hidden == true){   

               if (idoc.pageItems.name != typosafe) { 

                idoc.pageItems.remove()} 

               }   

            }   

 

// delete hidden layers 

function delete_hidden_layers () { 

    var myDoc = app.activeDocument; 

    var layerCount = myDoc.layers.length; 

        for (var ii = layerCount - 1; ii >= 0; ii--) { 

        var currentLayer = myDoc.layers[ii]; 

            currentLayer.locked = false; 

        var subCount = currentLayer.layers.length; 

        for (var ss = subCount -1; ss >= 0; ss--){ 

        var subLayer = currentLayer.layers[ss]; 

        subLayer.locked = false; 

        if (subLayer.visible == false){ 

            subLayer.visible = true; 

            if (subLayer.name != typosafe) { 

                subLayer.remove()} 

            else { 

                subLayer.visible = false}; 

            } 

        } 

    if (currentLayer.visible == false){ 

        currentLayer.visible = true; 

         if (currentLayer.name != typosafe) { 

                currentLayer.remove()} 

            else { 

                currentLayer.visible = false}; 

        } 

    } 

 

// hide layer containing varnish 

function hide_lack () { 

    var docwht = app.activeDocument;   

    var myLayers1 = docwht.layers;   

    var HideName1 = varnish;   

    try {   

        HideLayer1 = myLayers1.getByName (HideName1);   

        HideLayer1.visible = false;   

        redraw();   

        }   

    catch (e) {}   

 

// hide layer containing white color 

function hide_sfweiss () { 

    var docwht = app.activeDocument;   

    var myLayers1 = docwht.layers;   

    var HideName1 = white;   

    try {   

        HideLayer1 = myLayers1.getByName (HideName1);   

        HideLayer1.visible = false;   

        redraw();   

        }   

    catch (e) {}   

 

// outline all fonts 

function fontvect (){ 

         var doc = app.activeDocument; 

         while (doc.textFrames.length != 0) {  

               doc.textFrames[0].createOutline();  

               } 

}

// collect fonts found in the document to sub-folder

function getUsedFonts(doc) {

    var xml = new XML(doc.XMPString),

        names = xml.descendants('stFnt:fontName'),

        files = xml.descendants('stFnt:fontFileName'),

        ln = names.length(),

        i = 0,

        arr = [];

    for (; i < ln; i++) {

        arr.push([names, files])

    };

    return arr;

}

function packageFonts(arr, oFolder) {

    Array.prototype.indexOf = function (obj, start) {

        for (var i = (start || 0), j = this.length; i < j; i++) {

            if (this === obj) {

                return i

            }

        }

        return -1

    }

    var oFile, oName, fontInfo, fontName, fontFiles, index, n,

        psNameArr = String(app.fonts.everyItem().postscriptName).split(','),

        arr = arr.split('###'),

        ln = arr.length,

        i = 0;

    for (; i < ln; i++) {

        fontInfo = arr.split(',');

        fontName = fontInfo[0];

        fontFiles = fontInfo[1].split('; ');

        index = psNameArr.indexOf(fontName);

        oPath = File(app.fonts[index].location).parent;

        for (n = 0; n < fontFiles.length; n++) {

            oFile = File(oPath + '/' + fontFiles);

            oName = oFolder + '/' + fontFiles;

            try {

                oFile.copy(File(oName), true)

            } catch (e) {}

        }

    }

};

function collectPackagedFonts() {

    var doc = app.activeDocument,

        arr = getUsedFonts(doc),

        oFolder = new Folder(destFolder + export_folder + "/" + '/Fonts'),

        bt;

    oFolder.create();

    bt = new BridgeTalk();

    bt.target = "indesign";

    bt.body = packageFonts.toSource() + '("' + arr.join('###') + '", "' + oFolder + '")';

    bt.send();

    oFolder.execute();

}

 

// load XMP Library 

function loadXMPLibrary() {   

         if (!ExternalObject.AdobeXMPScript) {   

            try {   

                ExternalObject.AdobeXMPScript = new ExternalObject('lib:AdobeXMPScript');   

            } catch (e) {   

              alert('Unable to load the AdobeXMPScript library!');   

              return false;   

            }   

        }   

        return true;   

}   

 

// unload XMP Library 

function unloadXMPLibrary() {   

         if (ExternalObject.AdobeXMPScript) {   

            try {   

                ExternalObject.AdobeXMPScript.unload();   

                ExternalObject.AdobeXMPScript = undefined;   

            } catch (e) {   

              alert('Unable to unload the AdobeXMPScript library!');   

            }   

        }   

}   

 

// list all used fonts in the document 

function list_fonts () { 

         var doc = app.activeDocument; 

         var fontsInfo = [];   

         loadXMPLibrary ();   

         fontsInfo.push (getFontsInfo (doc.fullName));   

         unloadXMPLibrary ();   

         var info = fontsInfo.join ('\n\n'); 

         return info; 

 

// search for all used fonts in the document with ful info 

function getFontsInfo(file) {  

        var arr = [],   

            xmpFile,  

            oXmp,  

            fontNumber,  

            i,  

            path,  

            fontname,  

            fonttype,  

            ns = 'http://ns.adobe.com/xap/1.0/t/pg/';   

        xmpFile = new XMPFile(file.fsName, XMPConst.UNKNOWN, XMPConst.OPEN_FOR_READ);   

        oXmp = xmpFile.getXMP();    

        fontNumber = oXmp.countArrayItems(ns, 'xmpTPg:Fonts');   

        xmpFile.closeFile(XMPConst.CLOSE_UPDATE_SAFELY);   

        if (fontNumber) {    

            for (i = 1; i <= fontNumber; i++) {   

                path = XMPUtils.composeArrayItemPath(ns, 'xmpTPg:Fonts', i);   

                fontname = oXmp.getStructField(ns, path, XMPConst.TYPE_FONT, 'fontName');   

                fonttype = oXmp.getStructField(ns, path, XMPConst.TYPE_FONT, 'fontType');   

                arr.push([fontname, ' \t(', fonttype, ')'].join(''));   

            }   

        }   

        return arr.join('\n');   

 

// generate .txt file with info about collected files, fonts used in the doc, and images 

function create_info (listImages) { 

        listImages = unique(listImages); 

        var doc = app.activeDocument;   

        var d = new Date (); 

        var ddyear = d.getYear(); 

            ddyear += 1900; 

        var ddmonth = d.getMonth(); 

        var ddday = d.getDate(); 

        var ddhour = d.getHours(); 

        var ddmin = d.getMinutes(); 

        if (ddmin < 10) {ddmin = "0"+ddmin}; 

        var Loginfo = new File (export_folder + '/' + name_infofile);   

            Loginfo.open ('w', 'TEXT', '????'); 

        var info = "This .zip file contains \n\n" + 

                   name_ai + "\n" + 

                   "< editable AI CS6 file > \n\n" + 

                   name_aizw + "\n" + 

                   "< editable AI CS6 file with outlined fonts> \n\n" + 

                   name_pdfprint + "\n" + 

                   "< printable PDF/X > \n\n" + 

                   name_pdfpreview + "\n" + 

                   "< preview PDF, not for printing >" + 

                   "\n\n\n___________________________________________________________________________\n" +  

                   "Placed images \n\n" + 

                   listImages.join('\n') +  

                   "\n\n\n___________________________________________________________________________\n" +  

                   "Fonts used \n\n" + 

                   list_fonts() +  

                   "\n\n\n___________________________________________________________________________\n" +  

                   "Colors used in document (not printing colors) \n\n" + 

                   usedSwatches () +  

                   "\n\n\n___________________________________________________________________________\n" +  

                   "Files collected on \n" + 

                   "\n" + 

                   ddday +"."+ ddmonth +"."+ ddyear +", " + ddhour +":"+ ddmin + 

                   "\n\n" + scptver; 

              info = info.replace (/%20/g, " "); 

            Loginfo.write(info);   

            Loginfo.close(); 

            } 

             

// collect images linked in the document in sub-folder 

function collect_images () { 

    var doc = app.activeDocument; 

    var listImages = [];  

    var listImageFiles = [];  

    var i, in_file, out_file; 

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

        in_file = doc.placedItems.file; 

        listImages.push (in_file.name);  

        listImageFiles.push (in_file);  

        listImages = unique (listImages);  

        listImageFiles = unique(listImageFiles);  

        } 

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

        if (doc.rasterItems.embedded) continue; 

        in_file = doc.rasterItems.file; 

        listImages.push (in_file.name);  

        listImageFiles.push (in_file);  

        listImages = unique (listImages);  

        listImageFiles = unique(listImageFiles);  

        } 

    var ii; 

    var in_file_name; 

    var howManyImages = listImageFiles.length; 

    for (ii = 0; ii < listImageFiles.length; ii++) { 

        in_file = listImageFiles[ii]; 

        in_file_name = listImages[ii]; 

        out_file = File(assets_folder + "/" + in_file_name); 

        in_file.copy(out_file); 

        } 

    create_info (listImages);  

 

// search array and delete double entries 

function unique(ain) {    

         var seen = {}    

         var aout = []    

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

             var elt = ain    

             if (!seen[elt]) {    

                aout.push(elt)    

                seen[elt] = true    

                }    

             }    

          return aout 

 

// save file as AI and return to base file 

function saveCopyAsAI (nameAI) { 

    var doc = app.activeDocument; 

    var packaged_file = null; 

        packaged_file = File (destFolder + export_folder + "/" + nameAI); 

    var save_options = new IllustratorSaveOptions(); 

        save_options.embedICCProfile = false; 

        save_options.pdfCompatible = true; 

    doc.saveAs (packaged_file, save_options); 

    doc.close (); 

    app.open (File (original_file)); 

 

// save file as PDF and return to base file 

function saveCopyAsPDF (setPDF, namePDF) { 

        var doc = app.activeDocument;   

        var options = null;     

            options = new PDFSaveOptions (); 

            options.pDFPreset = setPDF; 

            options.viewAfterSaving = false; 

        var targetFile = null; 

            targetFile = new File (destFolder + export_folder + "/" + namePDF);     

        doc.saveAs (targetFile, options); 

        doc.close (); 

        app.open (File (original_file)); 

 

// list used swatches 

function usedSwatches () { 

    var docRef = app.activeDocument; 

    var sInks = ""; 

    var iLength = activeDocument.inkList.length; 

    for (var i = 0; i < iLength; i++) { 

        sInks += docRef.inkList.name; 

        sInks += "\n"; 

        } 

    return (sInks); 

 

// delete unused swatches 

function DeleteUnusedSwatches () { 

    if (app.documents.length = 0) {return;} 

        var ActionSet = "QwertyflyScriptedActions"   

        var Action1Name = "KillSwatches"   

        var ActionString = '/version 3\n/name [ 24\n'+ Hexit(ActionSet) +'\n]\n/isOpen 0\n/actionCount 1\n/action-1 {\n/name [ 12\n'+ Hexit(Action1Name) +'\n]\n/keyIndex 0\n/colorIndex 0\n/isOpen 0\n/eventCount 2\n/event-1 {\n/useRulersIn1stQuadrant 1\n/internalName (ai_plugin_swatches)\n/localizedName [ 8\n5377617463686573\n]\n/isOpen 0\n/isOn 1\n/hasDialog 0\n/parameterCount 1\n/parameter-1 {\n/key 1835363957\n/showInPalette 1\n/type (enumerated)\n/name [ 17\n53656c65637420416c6c20556e75736564\n]\n/value 11\n}\n}\n/event-2 {\n/useRulersIn1stQuadrant 1\n/internalName (ai_plugin_swatches)\n/localizedName [ 8\n5377617463686573\n]\n/isOpen 0\n/isOn 1\n/hasDialog 1\n/showDialog 0\n/parameterCount 1\n/parameter-1 {\n/key 1835363957\n/showInPalette 1\n/type (enumerated)\n/name [ 13\n44656c65746520537761746368\n]\n/value 3\n}\n}\n}';   

        createAction(ActionString,ActionSet);      

        ActionString = null;     

        app.doScript(Action1Name, ActionSet, false);     

        app.unloadAction(ActionSet,"");     

 

function createAction (str,act) { 

    var f = new File('~/' + act+ '.aia'); 

    f.open('w');      

    f.write(str);      

    f.close();      

    app.loadAction(f);      

    f.remove();      

}   

 

function Hexit(str) { 

    var hex = ''; 

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

        hex += ''+str.charCodeAt(i).toString(16); 

        } 

    return hex; 

}   

 

// __________________________________________________________________________ // 

// MAIN 

function main () { 

    if (app.documents.length > 1) { 

        Window.alert ("Error! \nPlease make sure to have opened \nonly 1  document."); 

    }     

    else { 

        stwin (); 

        delete_hidden_layers (); 

        delete_hidden (); 

        DeleteUnusedSwatches(); 

        stwin_delhidden (); 

        if (!doc.saved) doc.save();  

        if (assets_folder.exists || assets_folder.create());  

        stwin_printfolder (); 

        stwin_imagefolder (); 

        collect_images ();

        stwin_images (); 

      collectPackagedFonts();

        saveCopyAsAI (name_ai); 

        stwin_cs6 (); 

        saveCopyAsPDF (pdfOption, name_pdfprint); 

        stwin_x3 (); 

        fontvect (); 

        stwin_fontvect (); 

        hide_sfweiss (); 

        stwin_sfweiss (); 

        hide_lack (); 

        stwin_lack (); 

        saveCopyAsPDF (pdfOption2, name_pdfpreview); 

        stwin_lowres (); 

        fontvect (); 

        saveCopyAsAI (name_aizw); 

        stwin_cs6zw (); 

        stwin_ende (); 

        statuswin.close (); 

        app.beep (); $.sleep(200); app.beep (); $.sleep(200); app.beep ();

        Window.alert ("E-Fish is done. \nHave a good day!"); 

        } 

 

// __________________________________________________________________________ // 

//START 

 

var weiter = confirm ('COLLECT PRINTERS FILES: \n'+ 

                      '1. all hidden layers will be deleted \n'+ 

                      '2. all hidden objects will be deleted \n'+ 

                      '3. all colors not in use will be deleted \n'+ 

                      'after that the cleaned up file will be saved.\n'+ 

                      'Images linked in this file will be collected.\n\n'+ 

                      'Naming conventions: \n'+ 

                      'varnish = layer for spot color varnish \n'+ 

                      'white = layer for spot color white \n\n'+ 

                      'Modified type with effects attached to it \n'+ 

                      'should be duplicated and outlined in advance. \n\n'+ 

                      'To preserve the original type from being deleted \n' + 

                      'rename the layer containing the type to mod_typo! \n\n'+ 

                      'Please make sure only 1 AI file is open! \n\n'+ 

                      'Go ahead?',"Hinweis"); 

if (weiter != true) { 

    Window.alert ("Script cancelled. No changes have been made.") 

    } 

else { 

    main (); 

    }; 

                                 

// __________________________________________________________________________ // 

//STATUS WINDOW  

 

function stwin () { 

    statuswin.add ('panel',[15, 15, 385, 220], "Tasks:"); 

    statuswin.add ('statictext',[30, 30, 285, 100], "clean up an save base file ..."); 

    statuswin.add ('statictext',[30, 45, 285, 100], "generate folder for collected files ..."); 

    statuswin.add ('statictext',[30, 60, 285, 100], "generate sub-folder for images ..."); 

    statuswin.add ('statictext',[30, 75, 285, 100], "collect images ..."); 

    statuswin.add ('statictext',[30, 75, 285, 100], "package fonts ..."); 

    statuswin.add ('statictext',[30, 90, 285, 100], "save AI file ..."); 

    statuswin.add ('statictext',[30, 105, 285, 100], "save printable PDF ..."); 

    statuswin.add ('statictext',[30, 120, 285, 100], "outline fonts ..."); 

    statuswin.add ('statictext',[30, 135, 285, 100], "hide layer containing white ..."); 

    statuswin.add ('statictext',[30, 150, 285, 100], "hide layer containing varnish ..."); 

    statuswin.add ('statictext',[30, 165, 285, 100], "save preview-only PDF ..."); 

    statuswin.add ('statictext',[30, 180, 285, 100], "save AI file with outlined fonts..."); 

    statuswin.add ('statictext',[30, 195, 285, 100], "collect used fonts ..."); 

 

    statuswin.pnl = statuswin.add("panel", [15, 215, 385, 300], "Files collected ...");   

    statuswin.pnl.progBar = statuswin.pnl.add("progressbar", [20, 30, 340, 50], 0, 100);   

    statuswin.pnl.progBarLabel = statuswin.pnl.add("statictext", [30, 33, 285, 235], "0%");   

 

    statuswin.add ('statictext',[15, 310, 285, 400], scptver); 

    statuswin.show (); 

    } 

 

function stwin_delhidden() { 

statuswin.add ('statictext',[305, 30, 345, 100], "done"); 

statuswin.update(); 

statuswin.pnl.progBar.value= 10;    

statuswin.pnl.progBarLabel.text = statuswin.pnl.progBar.value+"%";   

statuswin.update(); 

 

function stwin_printfolder() { 

statuswin.add ('statictext',[305, 45, 345, 100], "done"); 

statuswin.update(); 

statuswin.pnl.progBar.value= 15;    

statuswin.pnl.progBarLabel.text = statuswin.pnl.progBar.value+"%";   

statuswin.update(); 

 

function stwin_imagefolder() { 

statuswin.add ('statictext',[305, 60, 345, 100], "done"); 

statuswin.update(); 

statuswin.pnl.progBar.value= 20;    

statuswin.pnl.progBarLabel.text = statuswin.pnl.progBar.value+"%";   

statuswin.update(); 

 

function stwin_images() { 

statuswin.add ('statictext',[305, 75, 345, 100], "done"); 

statuswin.update(); 

statuswin.pnl.progBar.value= 30;    

statuswin.pnl.progBarLabel.text = statuswin.pnl.progBar.value+"%";   

statuswin.update(); 

 

function stwin_cs6() { 

statuswin.add ('statictext',[305, 90, 345, 100], "done"); 

statuswin.update(); 

statuswin.pnl.progBar.value= 40;    

statuswin.pnl.progBarLabel.text = statuswin.pnl.progBar.value+"%";   

statuswin.update(); 

 

function stwin_x3() { 

statuswin.add ('statictext',[305, 105, 345, 100], "done"); 

statuswin.update(); 

statuswin.pnl.progBar.value= 50;    

statuswin.pnl.progBarLabel.text = statuswin.pnl.progBar.value+"%";   

statuswin.update(); 

 

function stwin_fontvect() { 

statuswin.add ('statictext',[305, 120, 345, 100], "done"); 

statuswin.update(); 

statuswin.pnl.progBar.value= 55;    

statuswin.pnl.progBarLabel.text = statuswin.pnl.progBar.value+"%";   

statuswin.update(); 

 

function stwin_sfweiss() { 

statuswin.add ('statictext',[305, 135, 345, 100], "done"); 

statuswin.update(); 

statuswin.pnl.progBar.value= 65;    

statuswin.pnl.progBarLabel.text = statuswin.pnl.progBar.value+"%";   

statuswin.update(); 

 

function stwin_lack() { 

statuswin.add ('statictext',[305, 150, 345, 100], "done"); 

statuswin.update(); 

statuswin.pnl.progBar.value= 70;    

statuswin.pnl.progBarLabel.text = statuswin.pnl.progBar.value+"%";   

statuswin.update(); 

 

function stwin_lowres() { 

statuswin.add ('statictext',[305, 165, 345, 100], "done"); 

statuswin.update(); 

statuswin.pnl.progBar.value= 80;    

statuswin.pnl.progBarLabel.text = statuswin.pnl.progBar.value+"%";   

statuswin.update(); 

 

function stwin_cs6zw () { 

statuswin.add ('statictext',[305, 180, 345, 100], "done"); 

statuswin.update(); 

statuswin.pnl.progBar.value= 90;    

statuswin.pnl.progBarLabel.text = statuswin.pnl.progBar.value+"%";   

statuswin.update(); 

 

function stwin_ende() { 

statuswin.add ('statictext',[305, 195, 345, 100], "to do"); 

statuswin.update(); 

statuswin.pnl.progBar.value= 100;    

statuswin.pnl.progBarLabel.text = statuswin.pnl.progBar.value+"%";   

statuswin.update(); 

$.sleep(2000); 

}

Votes

Translate

Translate

Report

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