[
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\ngithub: objective-see\npatreon: objective_see\n\n"
  },
  {
    "path": ".gitignore",
    "content": "# Xcode\n#\n# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore\n\n## macOS\n.DS_Store\n\n## Build generated\nbuild/\nDerivedData/\n\n## Various settings\n*.pbxuser\n!default.pbxuser\n*.mode1v3\n!default.mode1v3\n*.mode2v3\n!default.mode2v3\n*.perspectivev3\n!default.perspectivev3\nxcuserdata/\n\n## Other\n*.moved-aside\n*.xccheckout\n*.xcscmblueprint\n\n## Obj-C/Swift specific\n*.hmap\n*.ipa\n*.dSYM.zip\n*.dSYM\n\n# Carthage\n#\n# Add this line if you want to avoid checking in source code from Carthage dependencies.\nCarthage/Build\nCarthage/Checkouts\nDMG/Release/*\nDMG/LuLu.app\nDMG/*.dmg\nDMG/background.psd\nLuLu/Binaries/\n"
  },
  {
    "path": "DMG/createDMG.sh",
    "content": "VERSION=$(/usr/libexec/PlistBuddy -c \"Print CFBundleVersion\" \"Release/LuLu.app/Contents/Info.plist\")\n\nprintf \"\\nCreating LuLu Disk Image...\\n\\n\"\n\ncreate-dmg \\\n  --volname \"LuLu v$VERSION\" \\\n  --volicon \"LuLu.icns\" \\\n  --background \"background.png\" \\\n  --window-pos 200 120 \\\n  --window-size 800 400 \\\n  --icon-size 100 \\\n  --icon \"LuLu.app\" 200 190 \\\n  --hide-extension \"LuLu.app\" \\\n  --app-drop-link 600 190 \\\n  \"LuLu_$VERSION.dmg\" \\\n  \"Release/\"\n\nprintf \"\\nCode signing dmg...\\n\"\n\ncodesign --force --sign \"Developer ID Application: Objective-See, LLC (VBG97UB4TA)\" LuLu_$VERSION.dmg\n\nprintf \"Done!\\n\"\n"
  },
  {
    "path": "LICENSE.md",
    "content": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The GNU General Public License is a free, copyleft license for\nsoftware and other kinds of works.\n\n  The licenses for most software and other practical works are designed\nto take away your freedom to share and change the works.  By contrast,\nthe GNU General Public License is intended to guarantee your freedom to\nshare and change all versions of a program--to make sure it remains free\nsoftware for all its users.  We, the Free Software Foundation, use the\nGNU General Public License for most of our software; it applies also to\nany other work released this way by its authors.  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthem if you wish), that you receive source code or can get it if you\nwant it, that you can change the software or use pieces of it in new\nfree programs, and that you know you can do these things.\n\n  To protect your rights, we need to prevent others from denying you\nthese rights or asking you to surrender the rights.  Therefore, you have\ncertain responsibilities if you distribute copies of the software, or if\nyou modify it: responsibilities to respect the freedom of others.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must pass on to the recipients the same\nfreedoms that you received.  You must make sure that they, too, receive\nor can get the source code.  And you must show them these terms so they\nknow their rights.\n\n  Developers that use the GNU GPL protect your rights with two steps:\n(1) assert copyright on the software, and (2) offer you this License\ngiving you legal permission to copy, distribute and/or modify it.\n\n  For the developers' and authors' protection, the GPL clearly explains\nthat there is no warranty for this free software.  For both users' and\nauthors' sake, the GPL requires that modified versions be marked as\nchanged, so that their problems will not be attributed erroneously to\nauthors of previous versions.\n\n  Some devices are designed to deny users access to install or run\nmodified versions of the software inside them, although the manufacturer\ncan do so.  This is fundamentally incompatible with the aim of\nprotecting users' freedom to change the software.  The systematic\npattern of such abuse occurs in the area of products for individuals to\nuse, which is precisely where it is most unacceptable.  Therefore, we\nhave designed this version of the GPL to prohibit the practice for those\nproducts.  If such problems arise substantially in other domains, we\nstand ready to extend this provision to those domains in future versions\nof the GPL, as needed to protect the freedom of users.\n\n  Finally, every program is threatened constantly by software patents.\nStates should not allow patents to restrict development and use of\nsoftware on general-purpose computers, but in those that do, we wish to\navoid the special danger that patents applied to a free program could\nmake it effectively proprietary.  To prevent this, the GPL assures that\npatents cannot be used to render the program non-free.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                       TERMS AND CONDITIONS\n\n  0. Definitions.\n\n  \"This License\" refers to version 3 of the GNU General Public License.\n\n  \"Copyright\" also means copyright-like laws that apply to other kinds of\nworks, such as semiconductor masks.\n\n  \"The Program\" refers to any copyrightable work licensed under this\nLicense.  Each licensee is addressed as \"you\".  \"Licensees\" and\n\"recipients\" may be individuals or organizations.\n\n  To \"modify\" a work means to copy from or adapt all or part of the work\nin a fashion requiring copyright permission, other than the making of an\nexact copy.  The resulting work is called a \"modified version\" of the\nearlier work or a work \"based on\" the earlier work.\n\n  A \"covered work\" means either the unmodified Program or a work based\non the Program.\n\n  To \"propagate\" a work means to do anything with it that, without\npermission, would make you directly or secondarily liable for\ninfringement under applicable copyright law, except executing it on a\ncomputer or modifying a private copy.  Propagation includes copying,\ndistribution (with or without modification), making available to the\npublic, and in some countries other activities as well.\n\n  To \"convey\" a work means any kind of propagation that enables other\nparties to make or receive copies.  Mere interaction with a user through\na computer network, with no transfer of a copy, is not conveying.\n\n  An interactive user interface displays \"Appropriate Legal Notices\"\nto the extent that it includes a convenient and prominently visible\nfeature that (1) displays an appropriate copyright notice, and (2)\ntells the user that there is no warranty for the work (except to the\nextent that warranties are provided), that licensees may convey the\nwork under this License, and how to view a copy of this License.  If\nthe interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n  1. Source Code.\n\n  The \"source code\" for a work means the preferred form of the work\nfor making modifications to it.  \"Object code\" means any non-source\nform of a work.\n\n  A \"Standard Interface\" means an interface that either is an official\nstandard defined by a recognized standards body, or, in the case of\ninterfaces specified for a particular programming language, one that\nis widely used among developers working in that language.\n\n  The \"System Libraries\" of an executable work include anything, other\nthan the work as a whole, that (a) is included in the normal form of\npackaging a Major Component, but which is not part of that Major\nComponent, and (b) serves only to enable use of the work with that\nMajor Component, or to implement a Standard Interface for which an\nimplementation is available to the public in source code form.  A\n\"Major Component\", in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system\n(if any) on which the executable work runs, or a compiler used to\nproduce the work, or an object code interpreter used to run it.\n\n  The \"Corresponding Source\" for a work in object code form means all\nthe source code needed to generate, install, and (for an executable\nwork) run the object code and to modify the work, including scripts to\ncontrol those activities.  However, it does not include the work's\nSystem Libraries, or general-purpose tools or generally available free\nprograms which are used unmodified in performing those activities but\nwhich are not part of the work.  For example, Corresponding Source\nincludes interface definition files associated with source files for\nthe work, and the source code for shared libraries and dynamically\nlinked subprograms that the work is specifically designed to require,\nsuch as by intimate data communication or control flow between those\nsubprograms and other parts of the work.\n\n  The Corresponding Source need not include anything that users\ncan regenerate automatically from other parts of the Corresponding\nSource.\n\n  The Corresponding Source for a work in source code form is that\nsame work.\n\n  2. Basic Permissions.\n\n  All rights granted under this License are granted for the term of\ncopyright on the Program, and are irrevocable provided the stated\nconditions are met.  This License explicitly affirms your unlimited\npermission to run the unmodified Program.  The output from running a\ncovered work is covered by this License only if the output, given its\ncontent, constitutes a covered work.  This License acknowledges your\nrights of fair use or other equivalent, as provided by copyright law.\n\n  You may make, run and propagate covered works that you do not\nconvey, without conditions so long as your license otherwise remains\nin force.  You may convey covered works to others for the sole purpose\nof having them make modifications exclusively for you, or provide you\nwith facilities for running those works, provided that you comply with\nthe terms of this License in conveying all material for which you do\nnot control copyright.  Those thus making or running the covered works\nfor you must do so exclusively on your behalf, under your direction\nand control, on terms that prohibit them from making any copies of\nyour copyrighted material outside their relationship with you.\n\n  Conveying under any other circumstances is permitted solely under\nthe conditions stated below.  Sublicensing is not allowed; section 10\nmakes it unnecessary.\n\n  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n\n  No covered work shall be deemed part of an effective technological\nmeasure under any applicable law fulfilling obligations under article\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\nsimilar laws prohibiting or restricting circumvention of such\nmeasures.\n\n  When you convey a covered work, you waive any legal power to forbid\ncircumvention of technological measures to the extent such circumvention\nis effected by exercising rights under this License with respect to\nthe covered work, and you disclaim any intention to limit operation or\nmodification of the work as a means of enforcing, against the work's\nusers, your or third parties' legal rights to forbid circumvention of\ntechnological measures.\n\n  4. Conveying Verbatim Copies.\n\n  You may convey verbatim copies of the Program's source code as you\nreceive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice;\nkeep intact all notices stating that this License and any\nnon-permissive terms added in accord with section 7 apply to the code;\nkeep intact all notices of the absence of any warranty; and give all\nrecipients a copy of this License along with the Program.\n\n  You may charge any price or no price for each copy that you convey,\nand you may offer support or warranty protection for a fee.\n\n  5. Conveying Modified Source Versions.\n\n  You may convey a work based on the Program, or the modifications to\nproduce it from the Program, in the form of source code under the\nterms of section 4, provided that you also meet all of these conditions:\n\n    a) The work must carry prominent notices stating that you modified\n    it, and giving a relevant date.\n\n    b) The work must carry prominent notices stating that it is\n    released under this License and any conditions added under section\n    7.  This requirement modifies the requirement in section 4 to\n    \"keep intact all notices\".\n\n    c) You must license the entire work, as a whole, under this\n    License to anyone who comes into possession of a copy.  This\n    License will therefore apply, along with any applicable section 7\n    additional terms, to the whole of the work, and all its parts,\n    regardless of how they are packaged.  This License gives no\n    permission to license the work in any other way, but it does not\n    invalidate such permission if you have separately received it.\n\n    d) If the work has interactive user interfaces, each must display\n    Appropriate Legal Notices; however, if the Program has interactive\n    interfaces that do not display Appropriate Legal Notices, your\n    work need not make them do so.\n\n  A compilation of a covered work with other separate and independent\nworks, which are not by their nature extensions of the covered work,\nand which are not combined with it such as to form a larger program,\nin or on a volume of a storage or distribution medium, is called an\n\"aggregate\" if the compilation and its resulting copyright are not\nused to limit the access or legal rights of the compilation's users\nbeyond what the individual works permit.  Inclusion of a covered work\nin an aggregate does not cause this License to apply to the other\nparts of the aggregate.\n\n  6. Conveying Non-Source Forms.\n\n  You may convey a covered work in object code form under the terms\nof sections 4 and 5, provided that you also convey the\nmachine-readable Corresponding Source under the terms of this License,\nin one of these ways:\n\n    a) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by the\n    Corresponding Source fixed on a durable physical medium\n    customarily used for software interchange.\n\n    b) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by a\n    written offer, valid for at least three years and valid for as\n    long as you offer spare parts or customer support for that product\n    model, to give anyone who possesses the object code either (1) a\n    copy of the Corresponding Source for all the software in the\n    product that is covered by this License, on a durable physical\n    medium customarily used for software interchange, for a price no\n    more than your reasonable cost of physically performing this\n    conveying of source, or (2) access to copy the\n    Corresponding Source from a network server at no charge.\n\n    c) Convey individual copies of the object code with a copy of the\n    written offer to provide the Corresponding Source.  This\n    alternative is allowed only occasionally and noncommercially, and\n    only if you received the object code with such an offer, in accord\n    with subsection 6b.\n\n    d) Convey the object code by offering access from a designated\n    place (gratis or for a charge), and offer equivalent access to the\n    Corresponding Source in the same way through the same place at no\n    further charge.  You need not require recipients to copy the\n    Corresponding Source along with the object code.  If the place to\n    copy the object code is a network server, the Corresponding Source\n    may be on a different server (operated by you or a third party)\n    that supports equivalent copying facilities, provided you maintain\n    clear directions next to the object code saying where to find the\n    Corresponding Source.  Regardless of what server hosts the\n    Corresponding Source, you remain obligated to ensure that it is\n    available for as long as needed to satisfy these requirements.\n\n    e) Convey the object code using peer-to-peer transmission, provided\n    you inform other peers where the object code and Corresponding\n    Source of the work are being offered to the general public at no\n    charge under subsection 6d.\n\n  A separable portion of the object code, whose source code is excluded\nfrom the Corresponding Source as a System Library, need not be\nincluded in conveying the object code work.\n\n  A \"User Product\" is either (1) a \"consumer product\", which means any\ntangible personal property which is normally used for personal, family,\nor household purposes, or (2) anything designed or sold for incorporation\ninto a dwelling.  In determining whether a product is a consumer product,\ndoubtful cases shall be resolved in favor of coverage.  For a particular\nproduct received by a particular user, \"normally used\" refers to a\ntypical or common use of that class of product, regardless of the status\nof the particular user or of the way in which the particular user\nactually uses, or expects or is expected to use, the product.  A product\nis a consumer product regardless of whether the product has substantial\ncommercial, industrial or non-consumer uses, unless such uses represent\nthe only significant mode of use of the product.\n\n  \"Installation Information\" for a User Product means any methods,\nprocedures, authorization keys, or other information required to install\nand execute modified versions of a covered work in that User Product from\na modified version of its Corresponding Source.  The information must\nsuffice to ensure that the continued functioning of the modified object\ncode is in no case prevented or interfered with solely because\nmodification has been made.\n\n  If you convey an object code work under this section in, or with, or\nspecifically for use in, a User Product, and the conveying occurs as\npart of a transaction in which the right of possession and use of the\nUser Product is transferred to the recipient in perpetuity or for a\nfixed term (regardless of how the transaction is characterized), the\nCorresponding Source conveyed under this section must be accompanied\nby the Installation Information.  But this requirement does not apply\nif neither you nor any third party retains the ability to install\nmodified object code on the User Product (for example, the work has\nbeen installed in ROM).\n\n  The requirement to provide Installation Information does not include a\nrequirement to continue to provide support service, warranty, or updates\nfor a work that has been modified or installed by the recipient, or for\nthe User Product in which it has been modified or installed.  Access to a\nnetwork may be denied when the modification itself materially and\nadversely affects the operation of the network or violates the rules and\nprotocols for communication across the network.\n\n  Corresponding Source conveyed, and Installation Information provided,\nin accord with this section must be in a format that is publicly\ndocumented (and with an implementation available to the public in\nsource code form), and must require no special password or key for\nunpacking, reading or copying.\n\n  7. Additional Terms.\n\n  \"Additional permissions\" are terms that supplement the terms of this\nLicense by making exceptions from one or more of its conditions.\nAdditional permissions that are applicable to the entire Program shall\nbe treated as though they were included in this License, to the extent\nthat they are valid under applicable law.  If additional permissions\napply only to part of the Program, that part may be used separately\nunder those permissions, but the entire Program remains governed by\nthis License without regard to the additional permissions.\n\n  When you convey a copy of a covered work, you may at your option\nremove any additional permissions from that copy, or from any part of\nit.  (Additional permissions may be written to require their own\nremoval in certain cases when you modify the work.)  You may place\nadditional permissions on material, added by you to a covered work,\nfor which you have or can give appropriate copyright permission.\n\n  Notwithstanding any other provision of this License, for material you\nadd to a covered work, you may (if authorized by the copyright holders of\nthat material) supplement the terms of this License with terms:\n\n    a) Disclaiming warranty or limiting liability differently from the\n    terms of sections 15 and 16 of this License; or\n\n    b) Requiring preservation of specified reasonable legal notices or\n    author attributions in that material or in the Appropriate Legal\n    Notices displayed by works containing it; or\n\n    c) Prohibiting misrepresentation of the origin of that material, or\n    requiring that modified versions of such material be marked in\n    reasonable ways as different from the original version; or\n\n    d) Limiting the use for publicity purposes of names of licensors or\n    authors of the material; or\n\n    e) Declining to grant rights under trademark law for use of some\n    trade names, trademarks, or service marks; or\n\n    f) Requiring indemnification of licensors and authors of that\n    material by anyone who conveys the material (or modified versions of\n    it) with contractual assumptions of liability to the recipient, for\n    any liability that these contractual assumptions directly impose on\n    those licensors and authors.\n\n  All other non-permissive additional terms are considered \"further\nrestrictions\" within the meaning of section 10.  If the Program as you\nreceived it, or any part of it, contains a notice stating that it is\ngoverned by this License along with a term that is a further\nrestriction, you may remove that term.  If a license document contains\na further restriction but permits relicensing or conveying under this\nLicense, you may add to a covered work material governed by the terms\nof that license document, provided that the further restriction does\nnot survive such relicensing or conveying.\n\n  If you add terms to a covered work in accord with this section, you\nmust place, in the relevant source files, a statement of the\nadditional terms that apply to those files, or a notice indicating\nwhere to find the applicable terms.\n\n  Additional terms, permissive or non-permissive, may be stated in the\nform of a separately written license, or stated as exceptions;\nthe above requirements apply either way.\n\n  8. Termination.\n\n  You may not propagate or modify a covered work except as expressly\nprovided under this License.  Any attempt otherwise to propagate or\nmodify it is void, and will automatically terminate your rights under\nthis License (including any patent licenses granted under the third\nparagraph of section 11).\n\n  However, if you cease all violation of this License, then your\nlicense from a particular copyright holder is reinstated (a)\nprovisionally, unless and until the copyright holder explicitly and\nfinally terminates your license, and (b) permanently, if the copyright\nholder fails to notify you of the violation by some reasonable means\nprior to 60 days after the cessation.\n\n  Moreover, your license from a particular copyright holder is\nreinstated permanently if the copyright holder notifies you of the\nviolation by some reasonable means, this is the first time you have\nreceived notice of violation of this License (for any work) from that\ncopyright holder, and you cure the violation prior to 30 days after\nyour receipt of the notice.\n\n  Termination of your rights under this section does not terminate the\nlicenses of parties who have received copies or rights from you under\nthis License.  If your rights have been terminated and not permanently\nreinstated, you do not qualify to receive new licenses for the same\nmaterial under section 10.\n\n  9. Acceptance Not Required for Having Copies.\n\n  You are not required to accept this License in order to receive or\nrun a copy of the Program.  Ancillary propagation of a covered work\noccurring solely as a consequence of using peer-to-peer transmission\nto receive a copy likewise does not require acceptance.  However,\nnothing other than this License grants you permission to propagate or\nmodify any covered work.  These actions infringe copyright if you do\nnot accept this License.  Therefore, by modifying or propagating a\ncovered work, you indicate your acceptance of this License to do so.\n\n  10. Automatic Licensing of Downstream Recipients.\n\n  Each time you convey a covered work, the recipient automatically\nreceives a license from the original licensors, to run, modify and\npropagate that work, subject to this License.  You are not responsible\nfor enforcing compliance by third parties with this License.\n\n  An \"entity transaction\" is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an\norganization, or merging organizations.  If propagation of a covered\nwork results from an entity transaction, each party to that\ntransaction who receives a copy of the work also receives whatever\nlicenses to the work the party's predecessor in interest had or could\ngive under the previous paragraph, plus a right to possession of the\nCorresponding Source of the work from the predecessor in interest, if\nthe predecessor has it or can get it with reasonable efforts.\n\n  You may not impose any further restrictions on the exercise of the\nrights granted or affirmed under this License.  For example, you may\nnot impose a license fee, royalty, or other charge for exercise of\nrights granted under this License, and you may not initiate litigation\n(including a cross-claim or counterclaim in a lawsuit) alleging that\nany patent claim is infringed by making, using, selling, offering for\nsale, or importing the Program or any portion of it.\n\n  11. Patents.\n\n  A \"contributor\" is a copyright holder who authorizes use under this\nLicense of the Program or a work on which the Program is based.  The\nwork thus licensed is called the contributor's \"contributor version\".\n\n  A contributor's \"essential patent claims\" are all patent claims\nowned or controlled by the contributor, whether already acquired or\nhereafter acquired, that would be infringed by some manner, permitted\nby this License, of making, using, or selling its contributor version,\nbut do not include claims that would be infringed only as a\nconsequence of further modification of the contributor version.  For\npurposes of this definition, \"control\" includes the right to grant\npatent sublicenses in a manner consistent with the requirements of\nthis License.\n\n  Each contributor grants you a non-exclusive, worldwide, royalty-free\npatent license under the contributor's essential patent claims, to\nmake, use, sell, offer for sale, import and otherwise run, modify and\npropagate the contents of its contributor version.\n\n  In the following three paragraphs, a \"patent license\" is any express\nagreement or commitment, however denominated, not to enforce a patent\n(such as an express permission to practice a patent or covenant not to\nsue for patent infringement).  To \"grant\" such a patent license to a\nparty means to make such an agreement or commitment not to enforce a\npatent against the party.\n\n  If you convey a covered work, knowingly relying on a patent license,\nand the Corresponding Source of the work is not available for anyone\nto copy, free of charge and under the terms of this License, through a\npublicly available network server or other readily accessible means,\nthen you must either (1) cause the Corresponding Source to be so\navailable, or (2) arrange to deprive yourself of the benefit of the\npatent license for this particular work, or (3) arrange, in a manner\nconsistent with the requirements of this License, to extend the patent\nlicense to downstream recipients.  \"Knowingly relying\" means you have\nactual knowledge that, but for the patent license, your conveying the\ncovered work in a country, or your recipient's use of the covered work\nin a country, would infringe one or more identifiable patents in that\ncountry that you have reason to believe are valid.\n\n  If, pursuant to or in connection with a single transaction or\narrangement, you convey, or propagate by procuring conveyance of, a\ncovered work, and grant a patent license to some of the parties\nreceiving the covered work authorizing them to use, propagate, modify\nor convey a specific copy of the covered work, then the patent license\nyou grant is automatically extended to all recipients of the covered\nwork and works based on it.\n\n  A patent license is \"discriminatory\" if it does not include within\nthe scope of its coverage, prohibits the exercise of, or is\nconditioned on the non-exercise of one or more of the rights that are\nspecifically granted under this License.  You may not convey a covered\nwork if you are a party to an arrangement with a third party that is\nin the business of distributing software, under which you make payment\nto the third party based on the extent of your activity of conveying\nthe work, and under which the third party grants, to any of the\nparties who would receive the covered work from you, a discriminatory\npatent license (a) in connection with copies of the covered work\nconveyed by you (or copies made from those copies), or (b) primarily\nfor and in connection with specific products or compilations that\ncontain the covered work, unless you entered into that arrangement,\nor that patent license was granted, prior to 28 March 2007.\n\n  Nothing in this License shall be construed as excluding or limiting\nany implied license or other defenses to infringement that may\notherwise be available to you under applicable patent law.\n\n  12. No Surrender of Others' Freedom.\n\n  If conditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot convey a\ncovered work so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you may\nnot convey it at all.  For example, if you agree to terms that obligate you\nto collect a royalty for further conveying from those to whom you convey\nthe Program, the only way you could satisfy both those terms and this\nLicense would be to refrain entirely from conveying the Program.\n\n  13. Use with the GNU Affero General Public License.\n\n  Notwithstanding any other provision of this License, you have\npermission to link or combine any covered work with a work licensed\nunder version 3 of the GNU Affero General Public License into a single\ncombined work, and to convey the resulting work.  The terms of this\nLicense will continue to apply to the part which is the covered work,\nbut the special requirements of the GNU Affero General Public License,\nsection 13, concerning interaction through a network will apply to the\ncombination as such.\n\n  14. Revised Versions of this License.\n\n  The Free Software Foundation may publish revised and/or new versions of\nthe GNU General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\n  Each version is given a distinguishing version number.  If the\nProgram specifies that a certain numbered version of the GNU General\nPublic License \"or any later version\" applies to it, you have the\noption of following the terms and conditions either of that numbered\nversion or of any later version published by the Free Software\nFoundation.  If the Program does not specify a version number of the\nGNU General Public License, you may choose any version ever published\nby the Free Software Foundation.\n\n  If the Program specifies that a proxy can decide which future\nversions of the GNU General Public License can be used, that proxy's\npublic statement of acceptance of a version permanently authorizes you\nto choose that version for the Program.\n\n  Later license versions may give you additional or different\npermissions.  However, no additional obligations are imposed on any\nauthor or copyright holder as a result of your choosing to follow a\nlater version.\n\n  15. Disclaimer of Warranty.\n\n  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\nAPPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\nOF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\nIS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\nALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. Limitation of Liability.\n\n  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\nTHE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\nUSE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\nDATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\nPARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\nEVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGES.\n\n  17. Interpretation of Sections 15 and 16.\n\n  If the disclaimer of warranty and limitation of liability provided\nabove cannot be given local legal effect according to their terms,\nreviewing courts shall apply local law that most closely approximates\nan absolute waiver of all civil liability in connection with the\nProgram, unless a warranty or assumption of liability accompanies a\ncopy of the Program in return for a fee.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nstate the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nAlso add information on how to contact you by electronic and paper mail.\n\n  If the program does terminal interaction, make it output a short\nnotice like this when it starts in an interactive mode:\n\n    <program>  Copyright (C) <year>  <name of author>\n    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, your program's commands\nmight be different; for a GUI interface, you would use an \"about box\".\n\n  You should also get your employer (if you work as a programmer) or school,\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.\nFor more information on this, and how to apply and follow the GNU GPL, see\n<https://www.gnu.org/licenses/>.\n\n  The GNU General Public License does not permit incorporating your program\ninto proprietary programs.  If your program is a subroutine library, you\nmay consider it more useful to permit linking proprietary applications with\nthe library.  If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License.  But first, please read\n<https://www.gnu.org/licenses/why-not-lgpl.html>.\n"
  },
  {
    "path": "LuLu/App/3rd-party/OrderedDictionary.h",
    "content": "//\n//  OrderedDictionary.h\n//  OrderedDictionary\n//\n//  Created by Matt Gallagher on 19/12/08.\n//  Copyright 2008 Matt Gallagher. All rights reserved.\n//\n//  This software is provided 'as-is', without any express or implied\n//  warranty. In no event will the authors be held liable for any damages\n//  arising from the use of this software. Permission is granted to anyone to\n//  use this software for any purpose, including commercial applications, and to\n//  alter it and redistribute it freely, subject to the following restrictions:\n//\n//  1. The origin of this software must not be misrepresented; you must not\n//     claim that you wrote the original software. If you use this software\n//     in a product, an acknowledgment in the product documentation would be\n//     appreciated but is not required.\n//  2. Altered source versions must be plainly marked as such, and must not be\n//     misrepresented as being the original software.\n//  3. This notice may not be removed or altered from any source\n//     distribution.\n//\n\n@import Cocoa;\n\n@interface OrderedDictionary : NSMutableDictionary\n{\n\tNSMutableDictionary *dictionary;\n\tNSMutableArray *array;\n}\n\n/* METHODS */\n-(void)reverse;\n-(id)keyAtIndex:(NSUInteger)anIndex;\n-(void)insertObject:(id)anObject forKey:(id)aKey atIndex:(NSUInteger)anIndex;\n\n@end\n"
  },
  {
    "path": "LuLu/App/3rd-party/OrderedDictionary.m",
    "content": "//\n//  OrderedDictionary.m\n//  OrderedDictionary\n//\n//  Created by Matt Gallagher on 19/12/08.\n//  Copyright 2008 Matt Gallagher. All rights reserved.\n//\n//  This software is provided 'as-is', without any express or implied\n//  warranty. In no event will the authors be held liable for any damages\n//  arising from the use of this software. Permission is granted to anyone to\n//  use this software for any purpose, including commercial applications, and to\n//  alter it and redistribute it freely, subject to the following restrictions:\n//\n//  1. The origin of this software must not be misrepresented; you must not\n//     claim that you wrote the original software. If you use this software\n//     in a product, an acknowledgment in the product documentation would be\n//     appreciated but is not required.\n//  2. Altered source versions must be plainly marked as such, and must not be\n//     misrepresented as being the original software.\n//  3. This notice may not be removed or altered from any source\n//     distribution.\n//\n\n#import \"Consts.h\"\n#import \"OrderedDictionary.h\"\n\n\nNSString *DescriptionForObject(NSObject *object, id locale, NSUInteger indent)\n{\n\tNSString *objectString;\n\tif ([object isKindOfClass:[NSString class]])\n\t{\n\t\tobjectString = (NSString *)object;\n\t}\n\telse if ([object respondsToSelector:@selector(descriptionWithLocale:indent:)])\n\t{\n\t\tobjectString = [(NSDictionary *)object descriptionWithLocale:locale indent:indent];\n\t}\n\telse if ([object respondsToSelector:@selector(descriptionWithLocale:)])\n\t{\n\t\tobjectString = [(NSSet *)object descriptionWithLocale:locale];\n\t}\n\telse\n\t{\n\t\tobjectString = [object description];\n\t}\n\treturn objectString;\n}\n\n@implementation OrderedDictionary\n\n-(id)init\n{\n    self = [super init];\n    if (self != nil)\n    {\n        dictionary = [NSMutableDictionary dictionary];\n        array = [NSMutableArray array];\n    }\n    return self;\n}\n\n-(id)copy\n{\n\treturn [self mutableCopy];\n}\n\n-(id)mutableCopy\n{\n    OrderedDictionary* copy = nil;\n    \n    copy = [[OrderedDictionary alloc] init];\n    copy->array = [array mutableCopy];\n    copy->dictionary = [dictionary mutableCopy];\n    \n    return copy;\n}\n\n-(void)reverse\n{\n    [array setArray:[[array reverseObjectEnumerator] allObjects]];\n}\n\n-(void)setObject:(id)anObject forKey:(id)aKey\n{\n\tif(![dictionary objectForKey:aKey])\n\t{\n        //\n\t\t[array addObject:aKey];\n\t}\n\t[dictionary setObject:anObject forKey:aKey];\n}\n\n-(void)removeObjectForKey:(id)aKey\n{\n\t[dictionary removeObjectForKey:aKey];\n\t[array removeObject:aKey];\n}\n\n- (NSUInteger)count\n{\n\treturn [dictionary count];\n}\n\n-(id)objectForKey:(id)aKey\n{\n\treturn [dictionary objectForKey:aKey];\n}\n\n-(NSEnumerator *)keyEnumerator\n{\n\treturn [array objectEnumerator];\n}\n\n-(void)insertObject:(id)anObject forKey:(id)aKey atIndex:(NSUInteger)anIndex\n{\n    //remove old object\n\tif([dictionary objectForKey:aKey])\n\t{\n        //remove\n\t\t[self removeObjectForKey:aKey];\n\t}\n    \n    //adding at end?\n    // just append item\n    if(array.count == anIndex)\n    {\n        //add\n        [array addObject:aKey];\n    }\n    //insert object\n    else\n    {\n        //insert\n        [array insertObject:aKey atIndex:anIndex];\n    }\n    \n\t//add to dictionary\n\t[dictionary setObject:anObject forKey:aKey];\n}\n\n-(id)keyAtIndex:(NSUInteger)anIndex\n{\n    //object\n    id item = nil;\n    \n    if((nil == array) ||\n       (anIndex >= array.count))\n    {\n        //bail\n        goto bail;\n    }\n    \n    //extract item\n    item = [array objectAtIndex:anIndex];\n    \nbail:\n    \n    return item;\n}\n\n@end\n"
  },
  {
    "path": "LuLu/App/AboutWindowController.h",
    "content": "//\n//  file: AboutWindowController.h\n//  project: lulu (main app)\n//  description: 'about' window controller (header)\n//\n//  created by Patrick Wardle\n//  copyright (c) 2017 Objective-See. All rights reserved.\n//\n\n@import Cocoa;\n\n@interface AboutWindowController : NSWindowController <NSWindowDelegate>\n{\n    \n}\n\n/* PROPERTIES */\n\n//version label/string\n@property (weak) IBOutlet NSTextField *versionLabel;\n\n//patrons\n@property (unsafe_unretained) IBOutlet NSTextView *patrons;\n\n/* METHODS */\n\n//automatically invoked when user clicks any of the buttons\n// ->perform actions, such as loading patreon or products URL\n-(IBAction)buttonHandler:(id)sender;\n\n@end\n"
  },
  {
    "path": "LuLu/App/AboutWindowController.m",
    "content": "//\n//  file: AboutWindowController.m\n//  project: lulu (main app)\n//  description: 'about' window controller\n//\n//  created by Patrick Wardle\n//  copyright (c) 2017 Objective-See. All rights reserved.\n//\n\n#import \"consts.h\"\n#import \"utilities.h\"\n#import \"AboutWindowController.h\"\n\n@implementation AboutWindowController\n\n@synthesize patrons;\n@synthesize versionLabel;\n\n//automatically called when nib is loaded\n// ->center window\n-(void)awakeFromNib\n{\n    //center\n    [self.window center];\n}\n\n//automatically invoked when window is loaded\n// set to window to white, set app version, patrons, etc\n-(void)windowDidLoad\n{\n    //version\n    NSString* version = nil;\n    \n    //super\n    [super windowDidLoad];\n    \n    //not in dark mode?\n    // make window white\n    if(YES != isDarkMode())\n    {\n        //make white\n        self.window.backgroundColor = NSColor.whiteColor;\n    }\n    \n    //grab app version\n    version = getAppVersion();\n    if(nil == version)\n    {\n        //default\n        version = NSLocalizedString(@\"unknown\", @\"unknown\");\n    }\n    \n    //set version sting\n    self.versionLabel.stringValue = [NSString stringWithFormat:NSLocalizedString(@\"Version: %@\", @\"Version: %@\"), version];\n\n    //load patrons\n    self.patrons.string = [NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@\"patrons\" ofType:@\"txt\"] encoding:NSUTF8StringEncoding error:NULL];\n    if(nil == self.patrons.string)\n    {\n        //default\n        self.patrons.string = NSLocalizedString(@\"ERROR: failed to load patrons\", @\"ERROR: failed to load patrons\");\n    }\n\n    return;\n}\n\n//automatically invoked when window is closing\n// ->make window unmodal\n-(void)windowWillClose:(NSNotification *)notification\n{\n    //make un-modal\n    [[NSApplication sharedApplication] stopModal];\n    \n    return;\n}\n\n//automatically invoked when user clicks any of the buttons\n// perform actions, such as loading patreon or products URL\n-(IBAction)buttonHandler:(id)sender\n{\n    //support us button\n    if(((NSButton*)sender).tag == BUTTON_SUPPORT_US)\n    {\n        //open URL\n        // invokes user's default browser\n        [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:PATREON_URL]];\n    }\n    \n    //more info button\n    else if(((NSButton*)sender).tag == BUTTON_MORE_INFO)\n    {\n        //open URL\n        // invokes user's default browser\n        [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:PRODUCT_URL]];\n    }\n\n    return;\n}\n@end\n"
  },
  {
    "path": "LuLu/App/AddRuleWindowController.h",
    "content": "//\n//  file: AddRuleWindowController.h\n//  project: lulu\n//  description: 'add/edit rule' window controller (header)\n//\n//  created by Patrick Wardle\n//  copyright (c) 2017 Objective-See. All rights reserved.\n//\n\n@import Cocoa;\n@import OSLog;\n\n#import \"Rule.h\"\n\n@interface AddRuleWindowController : NSWindowController <NSTextFieldDelegate>\n\n/* PROPERTIES */\n\n//app/binary icon\n@property (weak) IBOutlet NSImageView *icon;\n\n//path to app/binary\n@property (weak) IBOutlet NSTextField *path;\n\n//endpoint address\n@property (weak) IBOutlet NSTextField *endpointAddr;\n\n//but indicating endpoint addr is a regex\n@property (weak) IBOutlet NSButton *isEndpointAddrRegex;\n\n//endpoint port\n@property (weak) IBOutlet NSTextField *endpointPort;\n\n//'add' button\n@property (weak) IBOutlet NSButton *addButton;\n\n//block button\n@property (weak) IBOutlet NSButton *blockButton;\n\n//allow button\n@property (weak) IBOutlet NSButton *allowButton;\n\n//(existing) rule\n@property (nonatomic, retain)Rule* rule;\n\n//info (to create/update rule)\n@property(nonatomic, retain) NSDictionary* info;\n\n\n/* METHODS */\n\n//'block'/'allow' button handler\n// just needed so buttons will toggle\n-(IBAction)radioButtonsHandler:(id)sender;\n\n//'browse' button handler\n// open a panel for user to select file\n-(IBAction)browseButtonHandler:(id)sender;\n\n//'cancel' button handler\n// returns NSModalResponseCancel\n-(IBAction)cancelButtonHandler:(id)sender;\n\n//'add' button handler\n// returns NSModalResponseOK\n-(IBAction)addButtonHandler:(id)sender;\n\n@end\n"
  },
  {
    "path": "LuLu/App/AddRuleWindowController.m",
    "content": "//\n//  file: AddRuleWindowController.h\n//  project: lulu\n//  description: 'add/edit rule' window controller\n//\n//  created by Patrick Wardle\n//  copyright (c) 2017 Objective-See. All rights reserved.\n//\n\n#import \"consts.h\"\n#import \"utilities.h\"\n#import \"AddRuleWindowController.h\"\n\n/* GLOBALS */\n\n//log handle\nextern os_log_t logHandle;\n\n@implementation AddRuleWindowController\n\n@synthesize rule;\n\n//automatically called when nib is loaded\n// center window, set some defaults such as icon\n-(void)awakeFromNib\n{\n    //set icon\n    self.icon.image = [[NSWorkspace sharedWorkspace] iconForFileType: NSFileTypeForHFSTypeCode(kGenericApplicationIcon)];\n    \n    //resize\n    [self.icon.image setSize:NSMakeSize(128, 128)];\n    \n    //set delegate for process path text field\n    self.path.delegate = self;\n    \n    //existing rule?\n    // prepopulate fields\n    if(nil != self.rule)\n    {\n        //set title\n        self.window.title = @\"Edit Exiting Rule\";\n        \n        //path\n        self.path.stringValue = self.rule.path;\n        \n        //endpoint addr\n        self.endpointAddr.stringValue = self.rule.endpointAddr;\n        \n        //regex button\n        if(YES == self.rule.isEndpointAddrRegex)\n        {\n            //on\n            self.isEndpointAddrRegex.state = NSControlStateValueOn;\n        }\n        \n        //endpoint port\n        self.endpointPort.stringValue = self.rule.endpointPort;\n        \n        //block?\n        if(RULE_STATE_BLOCK == self.rule.action.intValue)\n        {\n            //set\n            self.blockButton.state = NSControlStateValueOn;\n        }\n        //allow?\n        else\n        {\n            //set\n            self.allowButton.state = NSControlStateValueOn;\n        }\n        \n        //configure 'add' button\n        self.addButton.title = NSLocalizedString(@\"Update\", @\"Update\");\n        \n        //enable 'add' button\n        self.addButton.enabled = YES;\n        \n        //make add/edit button first responder\n        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (100 * NSEC_PER_MSEC)), dispatch_get_main_queue(), ^{\n            \n            //set first responder\n            [self.window makeFirstResponder:self.addButton];\n            \n        });\n\n    }\n    \n    //no rule\n    // just init some defaults\n    else\n    {\n        //'add' button should be disabled\n        // ...until user enters an app/binary\n        self.addButton.enabled = NO;\n    }\n\n    return;\n}\n\n//automatically called when editing start\n// update UI by resetting icon and disabling 'add' button\n-(void)controlTextDidBeginEditing:(NSNotification *)obj\n{\n    //reset icon\n    self.icon.image = [[NSWorkspace sharedWorkspace]\n                       iconForFileType: NSFileTypeForHFSTypeCode(kGenericApplicationIcon)];\n    \n    //resize\n    [self.icon.image setSize:NSMakeSize(128, 128)];\n    \n    //disable 'add' button\n    self.addButton.enabled = NO;\n    \n    return;\n}\n\n//automatically called when text changes\n// invoke helper to set icon, and enable/select 'add' button\n-(void)controlTextDidChange:(NSNotification *)notification\n{\n    //ignore everything but process path\n    if([notification object] != self.path)\n    {\n        //bail\n        goto bail;\n    }\n    \n    //update\n    [self updateUI];\n    \nbail:\n    \n    return;\n}\n\n//automatically called when 'enter' is hit\n// invoke helper to set icon, and enable/select 'add' button\n-(void)controlTextDidEndEditing:(NSNotification *)notification\n{\n    //ignore everything but process path\n    if([notification object] != self.path)\n    {\n        //bail\n        goto bail;\n    }\n    \n    //update\n    [self updateUI];\n    \n    //make 'add' selected\n    [self.window makeFirstResponder:self.addButton];\n    \nbail:\n    \n    return;\n}\n\n//'block'/'allow' button handler\n// just needed so buttons will toggle\n-(IBAction)radioButtonsHandler:(id)sender\n{\n    return;\n}\n\n//'browse' button handler\n//  open a panel for user to select file\n-(IBAction)browseButtonHandler:(id)sender\n{\n    //'browse' panel\n    NSOpenPanel *panel = nil;\n    \n    //response to 'browse' panel\n    NSInteger response = 0;\n    \n    //init panel\n    panel = [NSOpenPanel openPanel];\n    \n    //allow files\n    panel.canChooseFiles = YES;\n    \n    //allow directories (app bundles)\n    panel.canChooseDirectories = YES;\n    \n    //can open app bundles\n    panel.treatsFilePackagesAsDirectories = YES;\n    \n    //start in /Apps\n    panel.directoryURL = [NSURL fileURLWithPath:@\"/Applications\"];\n    \n    //disable multiple selections\n    panel.allowsMultipleSelection = NO;\n    \n    //show it\n    response = [panel runModal];\n    \n    //ignore cancel\n    if(NSModalResponseCancel == response)\n    {\n        //bail\n        goto bail;\n    }\n    \n    //set text\n    self.path.stringValue = panel.URL.path;\n    \n    //update UI\n    [self updateUI];\n    \n    //make 'add' selected\n    [self.window makeFirstResponder:self.addButton];\n\nbail:\n    \n    return;\n}\n\n//'cancel' button handler\n// close sheet, returning NSModalResponseCancel\n-(IBAction)cancelButtonHandler:(id)sender\n{\n    //dbg msg\n    os_log_debug(logHandle, \"user clicked: %{public}@\", ((NSButton*)sender).title);\n    \n    //stop/cancel\n    [NSApp stopModalWithCode:NSModalResponseCancel];\n    \n    //close\n    [self.window close];\n    \n    return;\n}\n\n//'add' button handler\n// close sheet, returning NSModalResponseOK\n-(IBAction)addButtonHandler:(id)sender\n{\n    //response\n    NSModalResponse response = NSModalResponseAbort;\n    \n    //path\n    NSMutableString* path = nil;\n    \n    //flag\n    BOOL exists = NO;\n    \n    //flag\n    BOOL isDirectory = NO;\n    \n    //(remote) endpoint addr\n    NSString* endpointAddr = nil;\n    \n    //flag\n    NSNumber* endpointAddrRegex = nil;\n    \n    //(remote) endpoint addr\n    NSString* endpointPort = nil;\n    \n    //action\n    NSNumber* action = nil;\n    \n    //error\n    NSError* error = nil;\n\n    //dbg msg\n    os_log_debug(logHandle, \"user clicked: %{public}@\", ((NSButton*)sender).title);\n\n    //init path\n    // and check\n    path = [self.path.stringValue mutableCopy];\n    if(0 == path.length)\n    {\n        //bail\n        goto bail;\n    }\n    \n    //set flags\n    // exists/is directory\n    exists = [NSFileManager.defaultManager fileExistsAtPath:path isDirectory:&isDirectory];\n\n    //if its a directory (but not bundle)\n    // add '/*' to make it directory rule\n    if( (YES == isDirectory) &&\n        (nil == [NSBundle bundleWithPath:path]))\n    {\n        //no '/'?\n        // ...append it\n        if(YES != [path hasSuffix:@\"/\"])\n        {\n            //append\n            [path appendString:@\"/\"];\n        }\n        \n        //add '*' to make it a directory rule\n        [path appendString:VALUE_ANY];\n    }\n    \n    //invalid path?\n    if( (YES != exists) ||\n        (0 == path.length) )\n    {\n        //error\n        // though only if its not '*' or '/*'\n        if(YES != [path hasSuffix:VALUE_ANY])\n        {\n            //show alert\n            showAlert(NSAlertStyleWarning, NSLocalizedString(@\"ERROR: invalid path\", @\"ERROR: invalid path\"), [NSString stringWithFormat:NSLocalizedString(@\"%@ does not exist!\", @\"%@ does not exist!\"), path], @[NSLocalizedString(@\"OK\", @\"OK\")]);\n        \n            //bail\n            goto bail;\n        }\n    }\n    \n    //endpoint addr\n    // or '*' if blank\n    endpointAddr = (0 != self.endpointAddr.stringValue.length) ? self.endpointAddr.stringValue : VALUE_ANY;\n    \n    //is endpoint addr regex?\n    // ...set var, but also validate\n    endpointAddrRegex = [NSNumber numberWithBool:(self.isEndpointAddrRegex.state == NSControlStateValueOn)];\n    if( (YES == endpointAddrRegex.boolValue) &&\n        (nil == [NSRegularExpression regularExpressionWithPattern:endpointAddr options:0 error:&error]) )\n    {\n        //show alert\n        showAlert(NSAlertStyleWarning, NSLocalizedString(@\"ERROR: invalid regex\", @\"ERROR: invalid regex\"), [NSString stringWithFormat:NSLocalizedString(@\"%@ is not a valid regular expression\\r\\ndetails: %@\", @\"%@ is not a valid regular expression\\r\\ndetails: %@\"), endpointAddr, error.localizedDescription], @[NSLocalizedString(@\"OK\", @\"OK\")]);\n        \n        //bail\n        goto bail;\n    }\n\n    //endpoint port\n    // ...set var, but also validate\n    endpointPort = (0 != self.endpointPort.stringValue.length) ? self.endpointPort.stringValue : VALUE_ANY;\n    if( (0 != self.endpointPort.stringValue.length) &&\n        (YES != [self.endpointPort.stringValue isEqualToString:VALUE_ANY]) &&\n        (NSNotFound != [endpointPort rangeOfCharacterFromSet:[[NSCharacterSet decimalDigitCharacterSet] invertedSet]].location) )\n    {\n        //show alert\n        showAlert(NSAlertStyleWarning, NSLocalizedString(@\"ERROR: invalid port\", @\"ERROR: invalid port\"), [NSString stringWithFormat:NSLocalizedString(@\"%@ is not a valid (port) number\", @\"%@ is not a valid (port) number\"), endpointPort], @[NSLocalizedString(@\"OK\", @\"OK\")]);\n        \n        //bail\n        goto bail;\n    }\n\n    //set action\n    action = (self.blockButton.state == NSControlStateValueOn) ? @RULE_STATE_BLOCK : @RULE_STATE_ALLOW;\n    \n    //save all info\n    self.info = @{KEY_PATH:path,\n                  KEY_ENDPOINT_ADDR:endpointAddr,\n                  KEY_ENDPOINT_ADDR_IS_REGEX:endpointAddrRegex,\n                  KEY_ENDPOINT_PORT:endpointPort,\n                  KEY_TYPE:@RULE_TYPE_USER,\n                  KEY_ACTION:action};\n    \n    //ok happy\n    response = NSModalResponseOK;\n\nbail:\n    \n    //stop w/ response\n    [NSApp stopModalWithCode:response];\n    \n    //close\n    [self.window close];\n    \n    return;\n}\n\n//update the UI\n// set icon, and enable/select 'add' button\n-(void)updateUI\n{\n    //icon\n    NSImage* processIcon = nil;\n    \n    //blank\n    // disable 'add' button\n    if(0 == self.path.stringValue.length)\n    {\n        //set state\n        self.addButton.enabled = NO;\n        \n        //bail\n        goto bail;\n    }\n    \n    //get icon\n    processIcon = getIconForProcess(self.path.stringValue);\n    if(nil != processIcon)\n    {\n        //add\n        self.icon.image = processIcon;\n    }\n    \n    //enable 'add' button\n    self.addButton.enabled = YES;\n    \nbail:\n    \n    return;\n}\n\n//ensure title-bar close also ends the modal\n- (BOOL)windowShouldClose:(NSWindow *)sender {\n    [NSApp stopModalWithCode:NSModalResponseCancel];\n    return YES;\n}\n\n@end\n"
  },
  {
    "path": "LuLu/App/AlertWindowController.h",
    "content": "//\n//  file: AlertWindowController.h\n//  project: lulu (login item)\n//  description: window controller for main firewall alert (header)\n//\n//  created by Patrick Wardle\n//  copyright (c) 2017 Objective-See. All rights reserved.\n//\n\n@import Cocoa;\n@import OSLog;\n\n#import \"ParentsWindowController.h\"\n#import \"SigningInfoViewController.h\"\n\n@interface AlertWindowController : NSWindowController <NSTouchBarProvider, NSTouchBarDelegate>\n\n/* PROPERTIES */\n\n//alert info\n@property(nonatomic, retain)NSDictionary* alert;\n\n//touch bar\n@property(nonatomic, retain)NSTouchBar* touchBar;\n\n//reply\n@property (nonatomic, copy)void(^reply)(NSDictionary*);\n\n\n/* TOP */\n\n//process icon\n@property (weak) IBOutlet NSImageView *processIcon;\n\n//process name\n@property (weak) IBOutlet NSTextField *processName;\n\n//general alert message\n@property (unsafe_unretained) IBOutlet NSTextView *alertMessage;\n\n//signing info button\n@property (weak) IBOutlet NSButton *signingInfoButton;\n\n//signing info: popover\n@property (strong) IBOutlet NSPopover *signingInfoPopover;\n\n//virus total: button\n@property (weak) IBOutlet NSButton *virusTotalButton;\n\n\n//view controller for ancestry view/popover\n@property (weak) IBOutlet ParentsWindowController *ancestryViewController;\n\n//ancestry button\n@property (weak) IBOutlet NSButton *ancestryButton;\n\n//popover for ancestry\n@property (strong) IBOutlet NSPopover *ancestryPopover;\n\n//process ancestry\n@property (nonatomic, retain)NSMutableArray* processHierarchy;\n\n@property (weak) IBOutlet NSButton *allowButton;\n\n/* BOTTOM (DETAILS) */\n\n//process id\n@property (weak) IBOutlet NSTextField *processID;\n\n//process args\n@property (weak) IBOutlet NSTextField *processArgs;\n\n//process path\n@property (unsafe_unretained) IBOutlet NSTextView *processPath;\n\n//ip address\n@property (weak) IBOutlet NSTextField *ipAddress;\n\n//port/protocol\n@property (weak) IBOutlet NSTextField *portProto;\n\n//reverse dns name\n@property (unsafe_unretained) IBOutlet NSTextView *reverseDNS;\n\n//ancestry view\n@property (strong) IBOutlet NSView *ancestryView;\n\n//outline view in ancestry popover\n@property (weak) IBOutlet NSOutlineView *ancestryOutline;\n\n//text cell for ancestry popover\n@property (weak) IBOutlet NSTextFieldCell *ancestryTextCell;\n\n//time stamp\n@property (weak) IBOutlet NSTextField *timeStamp;\n\n//action (rule) scope\n@property (weak) IBOutlet NSPopUpButton *actionScope;\n\n//rule durations\n@property (weak) IBOutlet NSButton *ruleDurationAlways;\n@property (weak) IBOutlet NSButton *ruleDurationProcess;\n@property (weak) IBOutlet NSButton *ruleDurationCustom;\n@property (weak) IBOutlet NSTextField *ruleDurationHours;\n@property (weak) IBOutlet NSTextField *ruleDurationMinutes;\n\n//options view\n@property (weak) IBOutlet NSView *options;\n\n//show options button\n@property (weak) IBOutlet NSButton* showOptions;\n\n//endpoint (e.g. domain)\n@property(nonatomic, retain)NSString* endpoint;\n\n/* METHODS */\n\n//open signing info popover\n-(void)openSigningInfoPopover;\n\n//button handler\n// ->block/allow, and then close\n-(IBAction)handleUserResponse:(id)sender;\n\n//set wrapping\n-(void)setWrapping:(NSTextView *)textView;\n\n@end\n"
  },
  {
    "path": "LuLu/App/AlertWindowController.m",
    "content": "//\n//  file: AlertWindowController.m\n//  project: lulu\n//  description: window controller for main firewall alert\n//\n//  created by Patrick Wardle\n//  copyright (c) 2017 Objective-See. All rights reserved.\n//\n\n@import Foundation;\n#import <sys/socket.h>\n\n#import \"consts.h\"\n#import \"utilities.h\"\n#import \"AppDelegate.h\"\n#import \"XPCDaemonClient.h\"\n#import \"AlertWindowController.h\"\n\n/* GLOBALS */\n\n//log handle\nextern os_log_t logHandle;\n\n//xpc for daemon comms\nextern XPCDaemonClient* xpcDaemonClient;\n\n@implementation AlertWindowController\n\n@synthesize alert;\n@synthesize processIcon;\n@synthesize processName;\n@synthesize ancestryButton;\n@synthesize ancestryPopover;\n@synthesize processHierarchy;\n@synthesize virusTotalButton;\n@synthesize signingInfoButton;\n\n#define DEFAULT_WINDOW_HEIGHT 244\n#define DEFAULT_WINDOW_HEIGHT_EXPANDED 452\n\n//center window\n// also, transparency\n-(void)awakeFromNib\n{\n    //center\n    [self.window center];\n    \n    //full size content view for translucency\n    self.window.styleMask = self.window.styleMask | NSWindowStyleMaskFullSizeContentView;\n    \n    //title bar translucency\n    self.window.titlebarAppearsTransparent = YES;\n    \n    //move via background\n    self.window.movableByWindowBackground = YES;\n    \n    //set hour formatter\n    NSNumberFormatter *hoursFormatter = [[NSNumberFormatter alloc] init];\n    hoursFormatter.minimum = @0;\n    hoursFormatter.maximum = @23;\n    hoursFormatter.allowsFloats = NO;\n    self.ruleDurationHours.formatter = hoursFormatter;\n\n    //set minute formatter\n    NSNumberFormatter *minutesFormatter = [[NSNumberFormatter alloc] init];\n    minutesFormatter.minimum = @0;\n    minutesFormatter.maximum = @59;\n    minutesFormatter.allowsFloats = NO;\n    self.ruleDurationMinutes.formatter = minutesFormatter;\n    \n    return;\n}\n\n//delegate method\n// populate/configure alert window\n-(void)windowDidLoad\n{\n    //process pid\n    pid_t processID = 0;\n    \n    //process args\n    NSMutableString* arguments = nil;\n\n    //timestamp formatter\n    NSDateFormatter *timeFormat = nil;\n    \n    //paragraph style\n    NSMutableParagraphStyle* paragraphStyle = nil;\n    \n    //title attributes (for temporary label)\n    NSMutableDictionary* titleAttributes = nil;\n    \n    //preferences\n    NSDictionary* preferences = nil;\n    \n    //height\n    NSUInteger height = 0;\n    \n    //url\n    NSURL* url = nil;\n    \n    //selected duration\n    NSInteger lastRuleDurationTag = 0;\n    \n    //init paragraph style\n    paragraphStyle = [[NSMutableParagraphStyle alloc] init];\n    \n    //init dictionary for title attributes\n    titleAttributes = [NSMutableDictionary dictionary];\n    \n    //extract process ID\n    processID = [self.alert[KEY_PROCESS_ID] intValue];\n    \n    //get preferences\n    preferences = [xpcDaemonClient getPreferences];\n    \n    //do we have access?\n    // build hierarchy here\n    if(0 == kill(processID, 0))\n    {\n        //extract\n        self.processHierarchy = generateProcessHierarchy(processID);\n        \n        //dbg msg\n        os_log_debug(logHandle, \"(re)generated process hierarchy: %{public}@\", self.processHierarchy);\n    }\n    else\n    {\n        //extract\n        self.processHierarchy = alert[KEY_PROCESS_ANCESTORS];\n    }\n    \n    //disable ancestory button if no ancestors\n    if(0 == self.processHierarchy.count) \n    {\n        //disable\n        self.ancestryButton.enabled = NO;\n    }\n    \n    //disable VirusTotal button if preference is set\n    // this is enough, as all VT integration only occurs when user interacts with button\n    if(YES == [preferences[PREF_NO_VT_MODE] boolValue])\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"user has disabled VirusTotal integrations, so disabling VT button\");\n        \n        //disable\n        self.virusTotalButton.enabled = NO;\n    }\n    \n    //default to using url\n    // though we trim as we don't want the whole URL\n    if(nil != self.alert[KEY_URL])\n    {\n        //init url\n        url = [NSURL URLWithString:self.alert[KEY_URL]];\n        \n        //extract host\n        self.endpoint = url.host;\n    }\n    //use IP address\n    else\n    {\n        //set\n        self.endpoint = self.alert[KEY_HOST];\n    }\n    \n    //sanity check\n    if(nil == self.endpoint)\n    {\n        //set\n        self.endpoint = NSLocalizedString(@\"unknown\", @\"unknown\");\n    }\n    \n    /* TOP */\n    \n    //set process icon\n    self.processIcon.image = getIconForProcess(self.alert[KEY_PATH]);\n    \n    //process signing info\n    [self setSigningIcon];\n    \n    //set name\n    self.processName.stringValue = self.alert[KEY_PROCESS_NAME];\n    \n    //ensure process name clips\n    self.processName.wantsLayer = YES;\n    self.processName.layer.masksToBounds = YES;\n    \n    //alert message\n    self.alertMessage.string = [NSString stringWithFormat:NSLocalizedString(@\"is connecting to %@\", @\"is connecting to %@\"), self.endpoint];\n    \n    //set tooltip to full URL\n    if(nil != url)\n    {\n        //use (full) URLs\n        self.alertMessage.toolTip = [NSString stringWithFormat:NSLocalizedString(@\"Full URL: %@\", @\"Full URL: %@\"), url.absoluteString];\n    }\n    \n    /* BOTTOM (DETAILS) */\n    \n    //process pid\n    self.processID.stringValue = [self.alert[KEY_PROCESS_ID] stringValue];\n\n    //process args\n    // none? means error\n    if(0 == [self.alert[KEY_PROCESS_ARGS] count])\n    {\n        //unknown\n        self.processArgs.stringValue = NSLocalizedString(@\"unknown\", @\"unknown\");\n    }\n    //process args\n    // only one? means, argv[0] and none\n    else if(1 == [self.alert[KEY_PROCESS_ARGS] count])\n    {\n        //none\n        self.processArgs.stringValue = NSLocalizedString(@\"none\", @\"none\");\n    }\n    \n    //process args\n    // more than one? create string of all\n    else\n    {\n        //alloc\n        arguments = [NSMutableString string];\n        \n        //add each\n        // but skip argv[0]\n        for(NSUInteger i=0; i<[self.alert[KEY_PROCESS_ARGS] count]; i++)\n        {\n            //skip first\n            if(0 == i) continue;\n            \n            //add arg\n            [arguments appendFormat:@\"%@ \", [self.alert[KEY_PROCESS_ARGS] objectAtIndex:i]];\n        }\n        \n        //add to UI\n        self.processArgs.stringValue = arguments;\n    }\n    \n    //set tooltip\n    self.processArgs.toolTip = [NSString stringWithFormat:NSLocalizedString(@\"Process Arguments: %@\", @\"Process Arguments: %@\"), self.processArgs.stringValue];\n    \n    //process path for normal processes\n    if(YES != [self.alert[KEY_PROCESS_DELETED] boolValue])\n    {\n        //add as is\n        self.processPath.string = self.alert[KEY_PATH];\n    }\n    //deleted processes\n    // strike thru, so user knows\n    else\n    {\n        //strike thru\n        [self.processPath.textStorage setAttributedString: [[NSAttributedString alloc] initWithString:self.alert[KEY_PATH] attributes:@{NSStrikethroughStyleAttributeName:@(NSUnderlineStyleSingle)}]];\n    }\n    \n    //set wrapping\n    [self setWrapping:self.processPath];\n    \n    //set tooltip\n    self.processPath.toolTip = [NSString stringWithFormat:NSLocalizedString(@\"Process Path: %@\", @\"Process Path: %@\"), self.processPath.string];\n    \n    //ensure process path clips\n    self.processPath.wantsLayer = YES;\n    self.processPath.layer.masksToBounds = YES;\n        \n    //ip address\n    self.ipAddress.stringValue = (nil != self.alert[KEY_HOST]) ? self.alert[KEY_HOST] : NSLocalizedString(@\"unknown\", @\"unknown\");\n    \n    //port & proto\n    self.portProto.stringValue = [NSString stringWithFormat:@\"%@ (%@)\", self.alert[KEY_ENDPOINT_PORT], [self convertProtocol:self.alert[KEY_PROTOCOL]]];\n\n    //alloc time formatter\n    timeFormat = [[NSDateFormatter alloc] init];\n    \n    //set format\n    timeFormat.dateFormat = @\"HH:mm:ss\";\n    \n    //add timestamp\n    self.timeStamp.stringValue = [NSString stringWithFormat:NSLocalizedString(@\"Time stamp: %@\", @\"Time stamp: %@\"), [timeFormat stringFromDate:[[NSDate alloc] init]]];\n    \n    //set paragraph style to left\n    paragraphStyle.alignment = NSTextAlignmentLeft;\n    \n    //set paragraph attribute for temporary label\n    titleAttributes[NSParagraphStyleAttributeName] = paragraphStyle;\n    \n    //set color to label default\n    titleAttributes[NSForegroundColorAttributeName] = [NSColor labelColor];\n    \n    //set font\n    titleAttributes[NSFontAttributeName] = [NSFont fontWithName:@\"Menlo-Regular\" size:12];\n    \n    //process deleted?\n    // rule scope can only be temporary (as we don't have a path)\n    if(YES == [self.alert[KEY_PROCESS_DELETED] boolValue])\n    {\n        //on\n        self.ruleDurationProcess.state = NSControlStateValueOn;\n        \n        //disable others\n        self.ruleDurationAlways.enabled = NO;\n        self.ruleDurationCustom.enabled = NO;\n    }\n    //otherwise make sure others are (always) enabled\n    else\n    {\n        //enable\n        self.ruleDurationAlways.enabled = YES;\n        self.ruleDurationCustom.enabled = YES;\n    }\n\n    //set rule scope\n    // ...based on last one\n    [self.actionScope selectItemAtIndex:[preferences[PREF_ALERT_LAST_RULE_SCOPE] integerValue]];\n    \n    //grab last rule duration tag\n    lastRuleDurationTag = [preferences[PREF_ALERT_LAST_RULE_DURATION] integerValue];\n    \n    //not set\n    // default to always\n    if(0 == lastRuleDurationTag)\n    {\n        self.ruleDurationAlways.state = NSControlStateValueOn;\n    }\n    \n    //set rule duration\n    // ...based on last one\n    else if(lastRuleDurationTag == self.ruleDurationAlways.tag)\n    {\n        //set: on\n        self.ruleDurationAlways.state = NSControlStateValueOn;\n    }\n    else if(lastRuleDurationTag == self.ruleDurationProcess.tag)\n    {\n        //set: on\n        self.ruleDurationProcess.state = NSControlStateValueOn;\n    }\n    else if(lastRuleDurationTag == self.ruleDurationCustom.tag)\n    {\n        //set: on\n        self.ruleDurationCustom.state = NSControlStateValueOn;\n    }\n    \n    //show touch bar\n    [self initTouchBar];\n\n    //default height\n    height = DEFAULT_WINDOW_HEIGHT;\n    \n    //resize to handle size of alert\n    [self.window setFrame:NSMakeRect(self.window.frame.origin.x, self.window.frame.origin.y, self.window.frame.size.width, height) display:YES];\n    \n    //make 'allow' button first responder\n    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (100 * NSEC_PER_MSEC)), dispatch_get_main_queue(), ^{\n        \n        //set first responder\n        [self.window makeFirstResponder:self.allowButton];\n        \n    });\n    \n    //show details?\n    // if user expanded them on the last alert\n    if(NSControlStateValueOn == [preferences[PREF_ALERT_SHOW_OPTIONS] integerValue])\n    {\n        //set 'options' button state to on\n        self.showOptions.state = NSControlStateValueOn;\n        \n        //toggle, to show options\n        [self toggleOptionsView:self.showOptions];\n    }\n    //otherwise\n    // (re)set back to defaults\n    else\n    {\n        //default min\n        [self.window setContentMinSize:NSMakeSize(self.window.frame.size.width, DEFAULT_WINDOW_HEIGHT)];\n        \n        //default max\n        [self.window setContentMaxSize:NSMakeSize(self.window.frame.size.width, DEFAULT_WINDOW_HEIGHT)];\n        \n        //(re)set action scope\n        [self.actionScope selectItemAtIndex:ACTION_SCOPE_PROCESS];\n        \n        //(re)set rule scope\n        self.ruleDurationAlways.state = NSControlStateValueOn;\n    }\n    \nbail:\n    \n    return;\n}\n\n//covert number protocol to name\n-(NSString*)convertProtocol:(NSNumber*)protocol\n{\n    //protocol\n    NSString* name = nil;\n    \n    //convert\n    switch(protocol.intValue)\n    {\n        //tcp\n        case IPPROTO_TCP:\n            name = @\"TCP\";\n            break;\n            \n        //udp\n        case IPPROTO_UDP:\n            name = @\"UDP\";\n            break;\n            \n        //??\n        default:\n            name = [NSString stringWithFormat:NSLocalizedString(@\"<unknown (%d)>\", @\"<unknown (%d)>\"), [self.alert[KEY_PROTOCOL] intValue]];\n    }\n    \n    return name;\n}\n\n//set signing icon\n-(void)setSigningIcon\n{\n    //signing info\n    NSDictionary* signingInfo = nil;\n    \n    //extract\n    signingInfo = self.alert[KEY_CS_INFO];\n    \n    //dbg msg\n    os_log_debug(logHandle, \"signing info: %{public}@\", signingInfo);\n    \n    //none?\n    // just set to unknown\n    if(nil == signingInfo)\n    {\n        //set icon\n        signingInfoButton.image = [NSImage imageNamed:@\"SignedUnknown\"];\n        \n        //bail\n        goto bail;\n    }\n    \n    //parse signing info\n    switch([signingInfo[KEY_CS_STATUS] intValue])\n    {\n        //happily signed\n        case noErr:\n            \n            //item signed by apple\n            if(Apple == [signingInfo[KEY_CS_SIGNER] intValue])\n            {\n                //set icon\n                signingInfoButton.image = [NSImage imageNamed:@\"SignedApple\"];\n            }\n            //signed by dev id/ad hoc, etc\n            else\n            {\n                //set icon\n                signingInfoButton.image = [NSImage imageNamed:@\"Signed\"];\n            }\n            \n            break;\n            \n        //unsigned\n        case errSecCSUnsigned:\n            \n            //set icon\n            signingInfoButton.image = [NSImage imageNamed:@\"Unsigned\"];\n            \n            break;\n            \n        default:\n            \n            //set icon\n            signingInfoButton.image = [NSImage imageNamed:@\"SignedUnknown\"];\n    }\n    \nbail:\n    \n    return;\n}\n\n//automatically invoked when user clicks signing icon\n// depending on state, show/populate the popup, or close it\n-(IBAction)signingInfoButtonHandler:(id)sender\n{\n    //not open?\n    // show popover\n    if(YES != self.signingInfoPopover.isShown)\n    {\n        //open\n        [self openSigningInfoPopover];\n    }\n    \n    //otherwise close it\n    else\n    {\n        //close\n        [self.signingInfoPopover close];\n    }\n    \n    return;\n}\n\n//open signing info popover\n-(void)openSigningInfoPopover\n{\n    //view controller\n    SigningInfoViewController* popoverDelegate = nil;\n    \n    //set button state\n    self.signingInfoButton.state = NSControlStateValueOn;\n    \n    //grab delegate\n    popoverDelegate = (SigningInfoViewController*)self.signingInfoPopover.delegate;\n    \n    //set icon image\n    popoverDelegate.icon.image = self.signingInfoButton.image;\n    \n    //set alert info\n    popoverDelegate.alert = self.alert;\n    \n    //show popover\n    [self.signingInfoPopover showRelativeToRect:[self.signingInfoButton bounds] ofView:self.signingInfoButton preferredEdge:NSMaxYEdge];\n    \n    return;\n}\n\n//VT button handler\n// open user's browser w/ VT results\n-(IBAction)vtButtonHandler:(id)sender\n{\n    NSString* path = nil;\n    NSString* hash = nil;\n    \n    //default\n    path = self.processPath.string;\n    \n    //package?\n    // get path of binary from bundle\n    if ([[NSWorkspace sharedWorkspace] isFilePackageAtPath:self.processPath.string]) {\n        \n        //get path\n        path = getBundleExecutable(self.processPath.string);\n    }\n    \n    //hash\n    if(path) {\n        hash = hashFile(path);\n    }\n    if(hash) {\n        \n        //dbg msg\n        os_log_debug(logHandle, \"%{public}@ hashed to %{public}@ for VT\", path, hash);\n        \n        //open/show in browser\n        [NSWorkspace.sharedWorkspace openURL:[NSURL URLWithString:[NSString stringWithFormat:@\"https://www.virustotal.com/gui/file/%@\", hash]]];\n    }\n    //error\n    else {\n        \n        //show error\n        showAlert(NSAlertStyleWarning, [NSString stringWithFormat:NSLocalizedString(@\"ERROR: Failed to hash %@\", @\"ERROR: Failed to hash %@\"), self.processName.stringValue], nil, @[NSLocalizedString(@\"OK\", @\"OK\")]);\n    }\n    \n    return;\n}\n\n//invoked when user clicks process ancestry button\n// depending on state, show/populate the popup, or close it\n-(IBAction)ancestryButtonHandler:(id)sender\n{\n    //open popover\n    if(NSControlStateValueOn == self.ancestryButton.state)\n    {\n        //add the index value to each process in the hierarchy\n        // used to populate outline/table\n        for(NSUInteger i = 0; i<self.processHierarchy.count; i++)\n        {\n            //set index\n            self.processHierarchy[i][@\"index\"] = [NSNumber numberWithInteger:i];\n        }\n\n        //set process hierarchy\n        self.ancestryViewController.processHierarchy = processHierarchy;\n        \n        //dynamically (re)size popover\n        [self setPopoverSize];\n        \n        //reload it\n        [self.ancestryOutline reloadData];\n        \n        //auto-expand\n        [self.ancestryOutline expandItem:nil expandChildren:YES];\n        \n        //show popover\n        [self.ancestryPopover showRelativeToRect:[self.ancestryButton bounds] ofView:self.ancestryButton preferredEdge:NSMaxYEdge];\n    }\n    \n    //close popover\n    else\n    {\n        //close\n        [self.ancestryPopover close];\n    }\n    \n    return;\n}\n\n//set the popover window size\n// make it roughly fit to content\n-(void)setPopoverSize\n{\n    //popover's frame\n    CGRect popoverFrame = {0};\n    \n    //required height\n    CGFloat popoverHeight = 0.0f;\n    \n    //text of current row\n    NSString* currentRow = nil;\n    \n    //width of current row\n    CGFloat currentRowWidth = 0.0f;\n    \n    //length of max line\n    CGFloat maxRowWidth = 0.0f;\n    \n    //extra rows\n    NSUInteger extraRows = 0;\n    \n    //when hierarchy is less than 4\n    // ->set (some) extra rows\n    if(self.ancestryViewController.processHierarchy.count < 4)\n    {\n        //5 total\n        extraRows = 4 - self.ancestryViewController.processHierarchy.count;\n    }\n    \n    //calc total window height\n    // ->number of rows + extra rows, * height\n    popoverHeight = (self.ancestryViewController.processHierarchy.count + extraRows + 2) * [self.ancestryOutline rowHeight];\n    \n    //get window's frame\n    popoverFrame = self.ancestryView.frame;\n    \n    //calculate max line width\n    for(NSUInteger i=0; i<self.ancestryViewController.processHierarchy.count; i++)\n    {\n        //generate text of current row\n        currentRow = [NSString stringWithFormat:NSLocalizedString(@\"%@ (pid: %@)\", @\"%@ (pid: %@)\"), self.ancestryViewController.processHierarchy[i][@\"name\"], [self.ancestryViewController.processHierarchy lastObject][@\"pid\"]];\n        \n        //calculate width\n        // ->first w/ indentation\n        currentRowWidth = [self.ancestryOutline indentationPerLevel] * (i+1);\n        \n        //calculate width\n        // ->then size of string in row\n        currentRowWidth += [currentRow sizeWithAttributes: @{NSFontAttributeName: self.ancestryTextCell.font}].width;\n        \n        //save it greater than max\n        if(maxRowWidth < currentRowWidth)\n        {\n            //save\n            maxRowWidth = currentRowWidth;\n        }\n    }\n    \n    //add some padding\n    // ->scroll bar, etc\n    maxRowWidth += 50;\n    \n    //set height\n    popoverFrame.size.height = popoverHeight;\n    \n    //set width\n    popoverFrame.size.width = maxRowWidth;\n    \n    //set new frame\n    self.ancestryView.frame = popoverFrame;\n    \n    return;\n}\n\n//close any open popups\n-(void)closePopups\n{\n    //process ancestry popup\n    if(NSControlStateValueOn == self.ancestryButton.state)\n    {\n        //close\n        [self.ancestryPopover close];\n        \n        //set button state to off\n        self.ancestryButton.state = NSControlStateValueOff;\n    }\n    \n    //signing info popup\n    if(NSControlStateValueOn == self.signingInfoButton.state)\n    {\n        //close\n        [self.signingInfoPopover close];\n        \n        //set button state to off\n        self.signingInfoButton.state = NSControlStateValueOff;\n    }\n    \n    return;\n}\n\n//button handler\n// close popups, grap user response/send to daemon, save 'preferences' (options shown, etc)\n-(IBAction)handleUserResponse:(id)sender\n{\n    //rule expiration\n    NSDate* expiration = nil;\n    \n    //show options state\n    NSInteger showOptionsState = 0;\n    \n    //rule scope index\n    NSInteger ruleScopeIndex = 0;\n    \n    //rule duration\n    NSInteger ruleDurationTag = 0;\n    \n    //response to daemon\n    NSMutableDictionary* alertResponse = nil;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"handling user response\");\n    \n    //grab state\n    showOptionsState = self.showOptions.state;\n    \n    //grab action scope index\n    ruleScopeIndex = self.actionScope.indexOfSelectedItem;\n    \n    //get selected rule duration\n    if(self.ruleDurationAlways.state == NSControlStateValueOn)\n    {\n        //save\n        ruleDurationTag = self.ruleDurationAlways.tag;\n    }\n    else if(self.ruleDurationProcess.state == NSControlStateValueOn)\n    {\n        //save\n        ruleDurationTag = self.ruleDurationProcess.tag;\n    }\n    else if(self.ruleDurationCustom.state == NSControlStateValueOn)\n    {\n        //save\n        ruleDurationTag = self.ruleDurationCustom.tag;\n    }\n\n    //init alert response\n    // start w/ copy of received alert\n    alertResponse = [self.alert mutableCopy];\n    \n    //set type as user\n    alertResponse[KEY_TYPE] = @(RULE_TYPE_USER);\n    \n    //add current user\n    alertResponse[KEY_USER_ID] = @(getuid());\n    \n    //add user response\n    alertResponse[KEY_ACTION] = @(((NSButton*)sender).tag);\n    \n    //add action scope\n    alertResponse[KEY_SCOPE] = @(ruleScopeIndex);\n\n    //rule duration temporary (pid)?\n    if(NSControlStateValueOn == self.ruleDurationProcess.state)\n    {\n        //set flag\n        alertResponse[KEY_DURATION_PROCESS] = @1;\n    }\n    \n    //rule duration temporary (expiration)?\n    else if(NSControlStateValueOn == self.ruleDurationCustom.state)\n    {\n        NSInteger hours  = self.ruleDurationHours.integerValue;\n        NSInteger minutes = self.ruleDurationMinutes.integerValue;\n        NSTimeInterval totalSeconds = (hours * 3600) + (minutes * 60);\n\n        //sanity check\n        if(totalSeconds <= 0)\n        {\n            \n            //lower window level (so alert can show above)\n            [self.window setLevel:NSNormalWindowLevel];\n            \n            //show error\n            showAlert(NSAlertStyleWarning, NSLocalizedString(@\"ERROR: Enter a non-zero duration\", @\"ERROR: Enter a non-zero duration\"), nil, @[NSLocalizedString(@\"OK\", @\"OK\")]);\n            \n            //(re)set window level\n            [self.window setLevel:NSPopUpMenuWindowLevel];\n                \n            //bail here\n            return;\n        }\n        //covert and add\n        else {\n            \n            //convert to data\n            expiration = [NSDate dateWithTimeIntervalSinceNow:totalSeconds];\n            \n            //dbg msg\n            os_log_debug(logHandle, \"rule expiration: %{public}@\", expiration);\n            \n            //add\n            alertResponse[KEY_DURATION_EXPIRATION] = expiration;\n        }\n    }\n    \n    //set endpoint addr\n    alertResponse[KEY_ENDPOINT_ADDR] = self.endpoint;\n    \n    //close popups\n    [self closePopups];\n    \n    //close window\n    [self.window close];\n    \n    //dbg msg\n    os_log_debug(logHandle, \"replying to alert %{public}@\", alertResponse);\n    \n    //reply\n    self.reply(alertResponse);\n    \n    //save preferences\n    // includes options shown/last action scope, etc.\n    [xpcDaemonClient updatePreferences:@{PREF_ALERT_SHOW_OPTIONS: @(showOptionsState),\n                                         PREF_ALERT_LAST_RULE_SCOPE: @(ruleScopeIndex),\n                                         PREF_ALERT_LAST_RULE_DURATION: @(ruleDurationTag)}];\n    \n    //set app's background/foreground state\n    [((AppDelegate*)[[NSApplication sharedApplication] delegate]) setActivationPolicy];\n    \n    return;\n}\n\n//init/show touch bar\n-(void)initTouchBar\n{\n    //touch bar items\n    NSArray *touchBarItems = nil;\n    \n    //alloc/init\n    self.touchBar = [[NSTouchBar alloc] init];\n    if(nil == self.touchBar)\n    {\n        //no touch bar?\n        goto bail;\n    }\n    \n    //set delegate\n    self.touchBar.delegate = self;\n    \n    //set id\n    self.touchBar.customizationIdentifier = @BUNDLE_ID;\n    \n    //init items\n    touchBarItems = @[@\".icon\", @\".label\", @\".block\", @\".allow\"];\n    \n    //set items\n    self.touchBar.defaultItemIdentifiers = touchBarItems;\n    \n    //set customization items\n    self.touchBar.customizationAllowedItemIdentifiers = touchBarItems;\n    \nbail:\n    \n    return;\n}\n\n//delegate method\n// init item for touch bar\n-(NSTouchBarItem *)touchBar:(NSTouchBar *)touchBar makeItemForIdentifier:(NSTouchBarItemIdentifier)identifier\n{\n    //icon view\n    NSImageView *iconView = nil;\n    \n    //icon\n    NSImage* icon = nil;\n    \n    //item\n    NSCustomTouchBarItem *touchBarItem = nil;\n    \n    //init item\n    touchBarItem = [[NSCustomTouchBarItem alloc] initWithIdentifier:identifier];\n    \n    //icon\n    if(YES == [identifier isEqualToString: @\".icon\" ])\n    {\n        //init icon view\n        iconView = [[NSImageView alloc] initWithFrame:NSMakeRect(0, 0, 30.0, 30.0)];\n        \n        //enable layer\n        [iconView setWantsLayer:YES];\n        \n        //set color\n        [iconView.layer setBackgroundColor:[[NSColor windowBackgroundColor] CGColor]];\n        \n        //mask\n        iconView.layer.masksToBounds = YES;\n        \n        //round corners\n        iconView.layer.cornerRadius = 3.0;\n        \n        //load icon image\n        icon = [NSImage imageNamed:@\"Icon\"];\n        \n        //set size\n        icon.size = CGSizeMake(30, 30);\n        \n        //add image\n        iconView.image = icon;\n        \n        //set view\n        touchBarItem.view = iconView;\n    }\n    \n    //label\n    else if(YES == [identifier isEqualToString:@\".label\"])\n    {\n        //item label\n        touchBarItem.view = [NSTextField labelWithString:[NSString stringWithFormat:@\"%@ %@\", self.processName.stringValue,self.alertMessage.string]];\n    }\n    \n    //block button\n    else if(YES == [identifier isEqualToString:@\".block\"])\n    {\n        //init button\n        touchBarItem.view = [NSButton buttonWithTitle: @\"Block\" target:self action: @selector(handleUserResponse:)];\n        \n        //set tag\n        // 0: block\n        ((NSButton*)touchBarItem.view).tag = 0;\n    }\n    \n    //allow button\n    else if(YES == [identifier isEqualToString:@\".allow\"])\n    {\n        //init button\n        touchBarItem.view = [NSButton buttonWithTitle: @\"Allow\" target:self action: @selector(handleUserResponse:)];\n        \n        //set tag\n        // 1: allow\n        ((NSButton*)touchBarItem.view).tag = 1;\n    }\n    \n    return touchBarItem;\n}\n\n//groups radio buttons\n-(IBAction)ruleDurationHandler:(id)sender {\n   \n    //need this method so radio buttons are mutually exclusive\n}\n\n//show / hide option view\n-(IBAction)toggleOptionsView:(id)sender {\n    \n    //frame\n    NSRect origin = {0};\n    \n    //dbg msg\n    os_log_debug(logHandle, \"toggling option's view, state: %ld\", (long)self.showOptions.state);\n\n    //frame\n    NSRect windowFrame = self.window.frame;\n\n    //on\n    if(NSControlStateValueOn == self.showOptions.state)\n    {\n        origin = self.window.contentView.frame;\n        origin.origin.y = self.window.contentView.frame.size.height;\n        \n        windowFrame.size.height += NSHeight(self.options.frame); //NSHeight(self.options.frame);\n        windowFrame.origin.y -= NSHeight(self.options.frame);\n        \n        [self.window setContentMinSize:NSMakeSize(self.window.frame.size.width, DEFAULT_WINDOW_HEIGHT_EXPANDED)];\n        [self.window setContentMaxSize:NSMakeSize(self.window.frame.size.width, DEFAULT_WINDOW_HEIGHT_EXPANDED)];\n        \n        [self.options setHidden:NO];\n        \n        [self.window layoutIfNeeded];\n        [self.window displayIfNeeded];\n        \n        //dbg msg\n        os_log_debug(logHandle, \"added option view to window\");\n    }\n    //off\n    else\n    {\n        //[self.options removeFromSuperview];\n        [self.options setHidden:YES];\n        \n        //dbg msg\n        os_log_debug(logHandle, \"removed option view from window\");\n        \n        windowFrame.size.height -= NSHeight(self.options.frame);\n        windowFrame.origin.y += NSHeight(self.options.frame);\n        \n        [self.window setContentMinSize:NSMakeSize(self.window.frame.size.width, DEFAULT_WINDOW_HEIGHT)];\n        [self.window setContentMaxSize:NSMakeSize(self.window.frame.size.width, DEFAULT_WINDOW_HEIGHT)];\n    }\n        \n    //resize\n    [self.window setFrame:windowFrame display:YES animate:YES];\n    \n    return;\n}\n\n//set wrapping\n-(void)setWrapping:(NSTextView*)textView {\n    \n    NSRange fullRange = {0,0};\n    NSMutableAttributedString* mutableAttrString = nil;\n    \n    mutableAttrString = [textView.textStorage mutableCopy];\n    fullRange = NSMakeRange(0, mutableAttrString.length);\n\n    [mutableAttrString enumerateAttributesInRange:fullRange\n                                            options:0\n                                         usingBlock:^(NSDictionary* attrs, NSRange range, BOOL *stop) {\n        \n        NSMutableParagraphStyle* mutableParagraphStyle = nil;\n        \n        NSParagraphStyle* existingStyle = attrs[NSParagraphStyleAttributeName];\n        if(nil != existingStyle)\n        {\n            mutableParagraphStyle = [existingStyle mutableCopy];\n        }\n        else\n        {\n            mutableParagraphStyle = [[NSMutableParagraphStyle alloc] init];\n        }\n        \n        mutableParagraphStyle.lineBreakMode = NSLineBreakByCharWrapping;\n        \n        NSMutableDictionary* newAttrs = [attrs mutableCopy];\n        newAttrs[NSParagraphStyleAttributeName] = mutableParagraphStyle;\n        [mutableAttrString setAttributes:newAttrs range:range];\n    }];\n    \n    [textView.textStorage setAttributedString:mutableAttrString];\n    \n    return;\n}\n\n@end\n"
  },
  {
    "path": "LuLu/App/App.entitlements",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>com.apple.developer.networking.networkextension</key>\n\t<array>\n\t\t<string>content-filter-provider-systemextension</string>\n\t</array>\n\t<key>com.apple.developer.system-extension.install</key>\n\t<true/>\n\t<key>com.apple.security.application-groups</key>\n\t<array>\n\t\t<string>$(TeamIdentifierPrefix)com.objective-see.lulu</string>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "LuLu/App/AppDelegate.h",
    "content": "//\n//  AppDelegate.h\n//  LuLu\n//\n//  Created by Patrick Wardle on 8/1/20.\n//  Copyright (c) 2020 Objective-See. All rights reserved.\n//\n\n@import Cocoa;\n@import OSLog;\n@import NetworkExtension;\n@import SystemExtensions;\n\n#import \"StatusBarItem.h\"\n#import \"XPCDaemonClient.h\"\n#import \"AboutWindowController.h\"\n#import \"PrefsWindowController.h\"\n#import \"RulesWindowController.h\"\n#import \"UpdateWindowController.h\"\n#import \"StartupWindowController.h\"\n#import \"WelcomeWindowController.h\"\n\n@interface AppDelegate : NSObject <NSApplicationDelegate>\n\n\n/* PROPERTIES */\n\n//configure window controller\n@property(nonatomic, retain)StartupWindowController* startupWindowController;\n\n//uninstall (deactivation) request\n@property(nonatomic, retain)OSSystemExtensionRequest *uninstallRequest;\n\n//welcome view controller\n@property(nonatomic, retain)WelcomeWindowController* welcomeWindowController;\n\n//status bar menu/sub-menus\n@property(strong) IBOutlet NSMenu* statusMenu;\n\n//profile menu item\n@property(strong) IBOutlet NSMenuItem *profilesMenuItem;\n\n//switch profile menu item\n@property (weak) IBOutlet NSMenuItem *profileSwitchMenuItem;\n\n//list of profiles mene\n@property (weak) IBOutlet NSMenu *profilesMenu;\n\n//status bar menu controller\n@property(nonatomic, retain)StatusBarItem* statusBarItemController;\n\n//about window controller\n@property(nonatomic, retain)AboutWindowController* aboutWindowController;\n\n//preferences window controller\n@property(nonatomic, retain)PrefsWindowController* prefsWindowController;\n\n//rules window controller\n@property(nonatomic, retain)RulesWindowController* rulesWindowController;\n\n//update window controller\n@property(nonatomic, retain)UpdateWindowController* updateWindowController;\n\n/* METHODS */\n\n//first launch?\n// check for install time(stamp)\n-(BOOL)isFirstTime;\n\n//finish up initializations\n-(void)completeInitialization:(NSDictionary*)initialPreferenes;\n\n//set app foreground/background\n// determined by the app's window count\n-(void)setActivationPolicy;\n\n//'rules' menu item handler\n// alloc and show rules window\n-(IBAction)showRules:(id)sender;\n\n//'preferences' menu item handler\n// alloc and show preferences window\n-(void)showPreferences:(NSString*)itemID;\n\n//preferences changed\n// for now, just check status bar icon setting\n-(void)preferencesChanged:(NSDictionary*)preferences;\n\n//profiles changed\n-(void)profilesChanged;\n\n//toggle (status) bar icon\n-(void)toggleIcon:(NSDictionary*)preferences;\n\n//quit\n-(IBAction)quit:(id)sender;\n\n//uninstall\n-(IBAction)uninstall:(id)sender;\n\n@end\n\n"
  },
  {
    "path": "LuLu/App/AppDelegate.m",
    "content": "//\n//  AppDelegate.m\n//  LuLu\n//\n//  Created by Patrick Wardle on 8/1/20.\n//  Copyright (c) 2020 Objective-See. All rights reserved.\n//\n\n#import \"consts.h\"\n#import \"utilities.h\"\n\n#import \"Update.h\"\n#import \"Configure.h\"\n#import \"Extension.h\"\n#import \"AppDelegate.h\"\n\n/* GLOBALS */\n\n//log handle\nextern os_log_t logHandle;\n\n//alert windows\nNSMutableDictionary* alerts = nil;\n\n//xpc for daemon comms\nXPCDaemonClient* xpcDaemonClient = nil;\n\n@interface AppDelegate ()\n\n@property (weak) IBOutlet NSWindow *window;\n\n@end\n\n@implementation AppDelegate\n\n@synthesize aboutWindowController;\n@synthesize prefsWindowController;\n@synthesize rulesWindowController;\n@synthesize updateWindowController;\n@synthesize startupWindowController;\n@synthesize statusBarItemController;\n@synthesize welcomeWindowController;\n\n//main app interface\n-(void)applicationDidFinishLaunching:(NSNotification *)aNotification\n{\n    //delay\n    NSInteger delay = 1;\n    \n    //current version\n    NSOperatingSystemVersion version = {0};\n    \n    //alert response\n    NSModalResponse response = 0;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"%s\", __PRETTY_FUNCTION__);\n\n    //don't relaunch\n    [NSApp disableRelaunchOnLogin];\n    \n    //v1.0 version installed?\n    // prompt / provide link to uninstall instructions / exit\n    if(YES == [NSFileManager.defaultManager fileExistsAtPath:[INSTALL_DIRECTORY stringByAppendingPathComponent:@\"LuLu.bundle\"]])\n    {\n        //show alert\n        response = showAlert(NSAlertStyleWarning, NSLocalizedString(@\"Old Version of LuLu Installed\", @\"Old Version of LuLu Installed\"), NSLocalizedString(@\"This must be uninstalled before continuing. Click 'More Info' to learn how to uninstall it\", @\"This must be uninstalled before continuing\\r\\n.Click 'More Info' to learn how to uninstall it.\"), @[NSLocalizedString(@\"More Info\", @\"More Info\"), NSLocalizedString(@\"Cancel\", @\"Cancel\")]);\n        \n        //open link to uninstall instructions\n        if(NSAlertSecondButtonReturn == response)\n        {\n            //open\n            [NSWorkspace.sharedWorkspace openURL:[NSURL URLWithString:[NSString stringWithFormat:@\"%@#uninstall_v1\", PRODUCT_URL]]];\n        }\n        \n        //(always) exit\n        [NSApplication.sharedApplication terminate:self];\n    }\n    \n    //Apple: item's w/ System Extensions must be run from /Applications 🤷🏻‍♂️\n    if(![NSBundle.mainBundle.bundlePath hasPrefix:@\"/Applications/\"])\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"LuLu running from %{public}@, not from within /Applications\", NSBundle.mainBundle.bundlePath);\n        \n        //show alert\n        showAlert(NSAlertStyleInformational, NSLocalizedString(@\"LuLu must run from within /Applications\\r\\n\", @\"LuLu must run from within /Applications\\r\\n\"), NSLocalizedString(@\"...please copy it into /Applications and re-launch.\", @\"...please copy it into /Applications and re-launch.\"), @[NSLocalizedString(@\"OK\",@\"OK\")]);\n        \n        //exit\n        [NSApplication.sharedApplication terminate:self];\n    }\n    \n    //first time?\n    // show/walk thru welcome screen(s)\n    // ...will call back here to complete initializations\n    if(YES == [self isFirstTime])\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"first launch, will kick off welcome window(s)\");\n        \n        //alloc window controller\n        welcomeWindowController = [[WelcomeWindowController alloc] initWithWindowNibName:@\"Welcome\"];\n        \n        //set activation policy\n        [self setActivationPolicy];\n        \n        //show window\n        [self.welcomeWindowController showWindow:self];\n        \n        //make front\n        [[NSRunningApplication currentApplication] activateWithOptions:(NSApplicationActivateAllWindows | NSApplicationActivateIgnoringOtherApps)];\n        \n        //make window front\n        [self.startupWindowController.window makeKeyAndOrderFront:nil];\n        \n        //install (self as) login item\n        if(YES != toggleLoginItem(NSBundle.mainBundle.bundleURL, ACTION_INSTALL_FLAG))\n        {\n            //err msg\n            os_log_error(logHandle, \"ERROR: failed to install self as login item\");\n            \n        }\n        //dbg msg\n        else\n        {\n            os_log_debug(logHandle, \"installed self as login item\");\n        }\n    }\n    \n    //subsequent launches...\n    // launch extension & complete initializations\n    else\n    {\n        //dbg\n        os_log_debug(logHandle, \"subsequent launch...\");\n        \n        //started by user?\n        // show startup msg....\n        if(YES == launchedByUser())\n        {\n            //dbg msg\n            os_log_debug(logHandle, \"showing startup window...\");\n            \n            //alloc/init\n            startupWindowController = [[StartupWindowController alloc] initWithWindowNibName:@\"StartupWindowController\"];\n            \n            //activate\n            if(@available(macOS 14.0, *)) {\n                [NSApp activate];\n            }\n            else\n            {\n                [NSApp activateIgnoringOtherApps:YES];\n            }\n            \n            //make window front\n            [self.startupWindowController.window makeKeyAndOrderFront:nil];\n            \n            //make it modal(ish)\n            [self.startupWindowController.window setLevel:NSPopUpMenuWindowLevel];\n            \n            //show window\n            [self.startupWindowController showWindow:nil];\n        }\n        \n        //grab OS version\n        version = NSProcessInfo.processInfo.operatingSystemVersion;\n\n        //macOS 15\n        // but less than 15.3? ...increase delay so users can see warning\n        if(version.majorVersion == 15 && version.minorVersion < 3) {\n            \n            //3 seconds\n            delay = 3;\n        }\n        \n        //wait a few seconds, so that startup window can show... then fade out\n        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, delay * NSEC_PER_SEC), dispatch_get_main_queue(),\n        ^{\n            //fade out\n            fadeOut(self.startupWindowController.window, 1.0f);\n            \n            //(re)activate extension\n            // this will call back to complete inits when done\n            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),\n            ^{\n                //extension\n                Extension* extension = nil;\n                \n                //wait semaphore\n                dispatch_semaphore_t semaphore = 0;\n                            \n                //init extension object\n                extension = [[Extension alloc] init];\n                \n                //init wait semaphore\n                semaphore = dispatch_semaphore_create(0);\n                \n                //kick off extension activation request\n                [extension toggleExtension:ACTION_ACTIVATE reply:^(NSError* error)\n                {\n                    //dbg msg\n                    os_log_debug(logHandle, \"extension 'activate' returned\");\n                    \n                    //error\n                    if(error)\n                    {\n                        //err msg\n                        os_log_error(logHandle, \"ERROR: failed to activate extension\");\n                        \n                        //show error on main thread\n                        dispatch_async(dispatch_get_main_queue(), ^{\n                            \n                            //show alert\n                            showAlert(NSAlertStyleCritical, NSLocalizedString(@\"ERROR: activation failed\", @\"ERROR: activation failed\"), NSLocalizedString(@\"failed to activate system/network extension\", @\"failed to activate system/network extension\"), @[NSLocalizedString(@\"OK\", @\"OK\")]);\n                            \n                            //exit\n                            [NSApplication.sharedApplication terminate:self];\n                            \n                        });\n                        \n                        return;\n                    }\n                    \n                    //dbg msg\n                    os_log_debug(logHandle, \"activated system extension, will now activate network filter...\");\n                    \n                    //(always) activate network filter\n                    // side affect is that it launches system extension\n                    if(YES != [[[Extension alloc] init] toggleNetworkExtension:ACTION_ACTIVATE])\n                    {\n                        //err msg\n                        os_log_error(logHandle, \"ERROR: failed to activate network filter\");\n                        \n                        //show alert/exit on main thread\n                        dispatch_async(dispatch_get_main_queue(),\n                        ^{\n                            //show alert\n                            showAlert(NSAlertStyleCritical, NSLocalizedString(@\"ERROR: activation failed\", @\"ERROR: activation failed\"), NSLocalizedString(@\"failed to activate network filter\",@\"failed to activate network filter\"), @[NSLocalizedString(@\"OK\", @\"OK\")]);\n                            \n                            //bye\n                            [NSApplication.sharedApplication terminate:self];\n                        });\n                    }\n                    \n                    //dbg msg\n                    os_log_debug(logHandle, \"network filter activated/enabled\");\n                    \n                    //wait to ensure extension is up an running\n                    do\n                    {\n                        //dbg msg\n                        os_log_debug(logHandle, \"waiting for %{public}@\", EXT_BUNDLE_ID);\n                        \n                        //nap\n                        [NSThread sleepForTimeInterval:0.25f];\n                        \n                    } while(YES != [extension isExtensionRunning]);\n                    \n                    //dbg msg\n                    os_log_debug(logHandle, \"%{public}@ is off and running\", EXT_BUNDLE_ID);\n                            \n                    //complete initialization on main thread\n                    dispatch_async(dispatch_get_main_queue(), ^{\n                        \n                        //complete initializations\n                        [self completeInitialization:nil];\n                        \n                    });\n                        \n                    //signal semaphore\n                    dispatch_semaphore_signal(semaphore);\n                    \n                }];\n                \n                //dbg msg\n                os_log_debug(logHandle, \"waiting system extension & network filter activation...\");\n                \n                //wait for extension semaphore\n                dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);\n                \n            });\n        });\n    }\n\nbail:\n    \n    return;\n}\n\n//first launch?\n// check for install time(stamp)\n-(BOOL)isFirstTime\n{\n   return (nil == [[NSMutableDictionary dictionaryWithContentsOfFile:[INSTALL_DIRECTORY stringByAppendingPathComponent:PREFS_FILE]] objectForKey:PREF_INSTALL_TIMESTAMP]);\n}\n\n//handle user double-clicks\n// app is (likely) already running as login item, so show (or) activate window\n-(BOOL)applicationShouldHandleReopen:(NSApplication *)sender hasVisibleWindows:(BOOL)hasVisibleWindows\n{\n    //extension\n    Extension* extension = nil;\n\n    //init extension object\n    extension = [[Extension alloc] init];\n    \n    //dbg msg\n    os_log_debug(logHandle, \"method '%s' invoked (hasVisibleWindows: %d)\", __PRETTY_FUNCTION__, hasVisibleWindows);\n    \n    //extention isn't running?\n    // show alert, otherwise things get confusing\n    if(YES != [extension isExtensionRunning])\n    {\n        //show alert\n        showAlert(NSAlertStyleInformational, NSLocalizedString(@\"LuLu's Network Extension Is Not Running\", @\"LuLu's Network Extension Is Not Running\"), NSLocalizedString(@\"Extensions must be manually approved via System Settings (General > Login Items & Extensions > Network Extensions).\",@\"Extensions must be manually approved via System Settings (General > Login Items & Extensions > Network Extensions).\"), @[NSLocalizedString(@\"OK\", @\"OK\")]);\n        \n        //bail\n        goto bail;\n    }\n    \n    //no visible window(s)\n    // default to show preferences\n    if(YES != hasVisibleWindows)\n    {\n        //show prefs\n        [self showPreferences:nil];\n    }\n    \nbail:\n    \n    return NO;\n}\n\n//'rules' menu item handler\n// alloc and show rules window\n-(IBAction)showRules:(id)sender\n{\n    //dbg msg\n    os_log_debug(logHandle, \"method '%s' invoked\", __PRETTY_FUNCTION__);\n    \n    //alloc rules window controller\n    if(nil == self.rulesWindowController)\n    {\n        //alloc\n        rulesWindowController = [[RulesWindowController alloc] initWithWindowNibName:@\"Rules\"];\n    }\n    \n    //configure (UI)\n    [self.rulesWindowController configure];\n    \n    //make active\n    [self makeActive:self.rulesWindowController];\n    \n    return;\n}\n\n//'preferences' menu item handler\n// alloc and show preferences window\n-(void)showPreferences:(NSString*)itemID\n{\n    //dbg msg\n    os_log_debug(logHandle, \"method '%s' invoked with %@\", __PRETTY_FUNCTION__, itemID);\n    \n    //alloc prefs window controller\n    if(nil == self.prefsWindowController)\n    {\n        //alloc\n        prefsWindowController = [[PrefsWindowController alloc] initWithWindowNibName:@\"Preferences\"];\n    }\n\n    //make active\n    [self makeActive:self.prefsWindowController];\n    \n    //select tab\n    [self.prefsWindowController switchTo:itemID];\n    \n    return;\n}\n\n//'about' menu item handler\n// alloc/show the about window\n-(IBAction)showAbout:(id)sender\n{\n    //dbg msg\n    os_log_debug(logHandle, \"method '%s' invoked\", __PRETTY_FUNCTION__);\n    \n    //alloc/init settings window\n    if(nil == self.aboutWindowController)\n    {\n        //alloc/init\n        aboutWindowController = [[AboutWindowController alloc] initWithWindowNibName:@\"AboutWindow\"];\n    }\n    \n    //center window\n    [self.aboutWindowController.window center];\n    \n    //show window\n    [self.aboutWindowController showWindow:self];\n\n    return;\n}\n\n//preferences changed\n// for now, just check status bar icon setting\n-(void)preferencesChanged:(NSDictionary*)preferences\n{\n    //dbg msg\n    os_log_debug(logHandle, \"method '%s' invoked\", __PRETTY_FUNCTION__);\n    \n    //trigger rules reload, because some prefs influence how rules are displayed\n    [[NSNotificationCenter defaultCenter] postNotificationName:RULES_CHANGED object:nil userInfo:nil];\n    \n    //update status bar\n    [self toggleIcon:preferences];\n    \n    return;\n}\n\n//profiles changed\n// update preferences window and status bar menu\n-(void)profilesChanged\n{\n    //dbg msg\n    os_log_debug(logHandle, \"method '%s' invoked\", __PRETTY_FUNCTION__);\n    \n    //tell preferences window\n    [self.prefsWindowController reload];\n    \n    //tell status menu\n    [self.statusBarItemController setProfile];\n\n    return;\n}\n\n//close window handler\n// close rules || pref window\n-(IBAction)closeWindow:(id)sender\n{\n    //dbg msg\n    os_log_debug(logHandle, \"method '%s' invoked\", __PRETTY_FUNCTION__);\n    \n    //key window\n    NSWindow *keyWindow = nil;\n    \n    //get key window\n    keyWindow = [[NSApplication sharedApplication] keyWindow];\n    \n    //close\n    // but only for rules/pref/about window\n    if( (keyWindow != self.aboutWindowController.window) &&\n        (keyWindow != self.prefsWindowController.window) &&\n        (keyWindow != self.rulesWindowController.window) )\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"key window is not rules or pref window, so ignoring...\");\n        \n        //ignore\n        goto bail;\n    }\n    \n    //close\n    [keyWindow close];\n    \n    //set activation policy\n    [self setActivationPolicy];\n    \nbail:\n    \n    return;\n}\n\n//make a window control/window front/active\n-(void)makeActive:(NSWindowController*)windowController\n{\n    //make foreground\n    [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];\n    \n    //center\n    [windowController.window center];\n    \n    //make it key window\n    [windowController.window makeKeyAndOrderFront:self];\n    \n    //front\n    [windowController.window orderFrontRegardless];\n        \n    //show it\n    [windowController showWindow:self];\n    \n    //activate\n    if(@available(macOS 14.0, *)) {\n        [NSApp activate];\n    }\n    else\n    {\n        [NSApp activateIgnoringOtherApps:YES];\n    }\n    \n    //activate ...more!\n    [[NSRunningApplication currentApplication] activateWithOptions:(NSApplicationActivateAllWindows | NSApplicationActivateIgnoringOtherApps)];\n    \n    return;\n}\n\n//toggle (status) bar icon\n-(void)toggleIcon:(NSDictionary*)preferences\n{\n    //dbg msg\n    os_log_debug(logHandle, \"method '%s' invoked\", __PRETTY_FUNCTION__);\n    \n    //should run with icon?\n    // init and show status bar item\n    if(YES != [preferences[PREF_NO_ICON_MODE] boolValue])\n    {\n        //already showing?\n        if(nil != self.statusBarItemController)\n        {\n            //bail\n            goto bail;\n        }\n        \n        //dbg msg\n        os_log_debug(logHandle, \"initializing status bar item/menu\");\n        \n        //alloc/load status bar icon/menu\n        statusBarItemController = [[StatusBarItem alloc] init:self.statusMenu preferences:(NSDictionary*)preferences];\n    }\n    \n    //run without icon\n    // remove status bar item\n    else\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"removing status bar item/menu\");\n        \n        //already removed?\n        if(nil == self.statusBarItemController)\n        {\n            //bail\n            goto bail;\n        }\n        \n        //remove status item\n        [self.statusBarItemController removeStatusItem];\n        \n        //unset\n        self.statusBarItemController = nil;\n    }\n    \nbail:\n    \n    return;\n}\n\n//set app foreground/background\n-(void)setActivationPolicy\n{\n    //visible window\n    BOOL visibleWindow = NO;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"method '%s' invoked\", __PRETTY_FUNCTION__);\n    \n    //find any visible windows\n    for(NSWindow* window in NSApp.windows)\n    {\n        //visible window?\n        // that's not status bar?\n        if( (YES == window.isVisible) &&\n            (YES != [window.className isEqualToString:@\"_NSPopoverWindow\"]) &&\n            (YES != [window.className isEqualToString:@\"NSStatusBarWindow\"]) )\n        {\n            //set flag\n            visibleWindow = YES;\n            \n            //done\n            break;\n        }\n    }\n    \n    //any windows?\n    // bring app to foreground\n    if(YES == visibleWindow)\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"window(s) visible, setting policy: NSApplicationActivationPolicyRegular\");\n        \n        //foreground\n        [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];\n    }\n    \n    //no more windows\n    // send app to background\n    else\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"window(s) not visible, setting policy: NSApplicationActivationPolicyAccessory\");\n        \n        //background\n        [NSApp setActivationPolicy:NSApplicationActivationPolicyAccessory];\n    }\n    \n    return;\n}\n\n//finish up initializations\n// includes enabling network ext if user hasn't disabled\n-(void)completeInitialization:(NSDictionary*)initialPreferences\n{\n    //preferences\n    NSDictionary* preferences = nil;\n       \n    //dbg msg\n    os_log_debug(logHandle, \"method '%s' invoked\", __PRETTY_FUNCTION__);\n    \n    //alloc array for alert (windows)\n    alerts = [NSMutableDictionary dictionary];\n    \n    //init extension comms\n    // establishes connection to extension\n    xpcDaemonClient = [[XPCDaemonClient alloc] init];\n    \n    //initial prefs?\n    // send to extension\n    if(nil != initialPreferences)\n    {\n        //set prefs\n        [xpcDaemonClient updatePreferences:initialPreferences];\n    }\n    \n    //always (reset) disabled\n    // always want enabled on (restart)\n    preferences = [xpcDaemonClient updatePreferences:@{PREF_IS_DISABLED:@NO}];\n    \n    //dbg msg\n    os_log_debug(logHandle, \"loaded preferences %{public}@\", preferences);\n    \n    //run with status bar icon?\n    if(YES != [preferences[PREF_NO_ICON_MODE] boolValue])\n    {\n        //alloc/load nib\n        statusBarItemController = [[StatusBarItem alloc] init:self.statusMenu preferences:(NSDictionary*)preferences];\n        \n        //dbg msg\n        os_log_debug(logHandle, \"initialized/loaded status bar (icon/menu)\");\n    }\n    else\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"running in 'no icon' mode (so no need for status bar)\");\n    }\n    \n    //cleanup any expired/temp rules\n    [xpcDaemonClient cleanupRules:NO];\n    \n    //automatically check for updates?\n    // skipped if launched by user (e.g. first time run)\n    if( (YES != launchedByUser()) &&\n        (YES != [preferences[PREF_NO_UPDATE_MODE] boolValue]) )\n    {\n        //after a 30 seconds\n        // check for updates in background\n        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 30 * NSEC_PER_SEC), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^\n        {\n            //dbg msg\n            os_log_debug(logHandle, \"checking for update...\");\n           \n            //check\n            [self check4Update];\n       });\n    }\n    \n    return;\n}\n\n//check for update\n-(void)check4Update\n{\n    //update obj\n    Update* update = nil;\n    \n    //init update obj\n    update = [[Update alloc] init];\n    \n    //check for update\n    // 'updateResponse newVersion:' method will be called when check is done\n    [update checkForUpdate:^(NSUInteger result, NSString* newVersion) {\n        \n        //handle response\n        // new version, show popup\n        switch(result)\n        {\n            //error\n            case Update_Error:\n                os_log_error(logHandle, \"ERROR: update check failed\");\n                break;\n                \n            //no updates\n            case Update_None:\n                os_log_debug(logHandle, \"no updates available\");\n                break;\n                \n            //this version of macOS, not supported\n            case Update_NotSupported:\n                \n                //dbg msg\n                os_log_debug(logHandle, \"update available, but not for this version of macOS\");\n                break;\n                \n            //new version\n            // show update window\n            case Update_Available:\n                \n                //dbg msg\n                os_log_debug(logHandle, \"a new version (%@) is available\", newVersion);\n\n                //alloc update window\n                self.updateWindowController = [[UpdateWindowController alloc] initWithWindowNibName:@\"UpdateWindow\"];\n                \n                //configure\n                [self.updateWindowController configure:[NSString stringWithFormat:NSLocalizedString(@\"a new version (%@) is available!\",@\"a new version (%@) is available!\"), newVersion]];\n                \n                //center window\n                [self.updateWindowController.window center];\n                \n                //show it\n                [self.updateWindowController showWindow:self];\n                \n                //invoke function in background that will make window modal\n                dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{\n                    \n                    //make modal\n                    makeModal(self.updateWindowController);\n                    \n                });\n            \n                break;\n        }\n    \n    }];\n    \n    return;\n}\n\n//quit button handler\n// do any cleanup, then exit\n-(IBAction)quit:(id)sender\n{\n    //response\n    NSModalResponse response = 0;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"function '%s' invoked\", __PRETTY_FUNCTION__);\n    \n    //show alert\n    response = showAlert(NSAlertStyleInformational, NSLocalizedString(@\"Quit LuLu?\", @\"Quit LuLu?\"), NSLocalizedString(@\"...this will terminate LuLu, until the next time you log in.\", @\"...this will terminate LuLu, until the next time you log in.\"), @[NSLocalizedString(@\"Quit\", @\"Quit\"), NSLocalizedString(@\"Cancel\", @\"Cancel\")]);\n    \n    //show alert\n    // cancel? ignore\n    if(NSAlertSecondButtonReturn == response)\n    {\n         //dbg msg\n         os_log_debug(logHandle, \"user canceled quitting\");\n         \n         //(re)background\n         [self setActivationPolicy];\n    }\n    //ok\n    // user wants to quit!\n    else\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"user confirmed quit\");\n        \n        //slight delay to let alert dismiss\n        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{\n                    \n            //config obj\n            Configure* configure = [[Configure alloc] init];\n            \n            //quit\n            [configure quit];\n            \n            //and terminate\n            [NSApplication.sharedApplication terminate:self];\n            \n        });\n    }\n    \n    return;\n}\n\n//uninstall menu handler\n// cleanup all the thingz!\n-(IBAction)uninstall:(id)sender\n{\n    //response\n    NSModalResponse response = 0;\n    \n    //config obj\n    Configure* configure = nil;\n    \n    //show alert\n    response = showAlert(NSAlertStyleInformational, NSLocalizedString(@\"Uninstall LuLu?\", @\"Uninstall LuLu?\"), NSLocalizedString(@\"...this will fully remove LuLu from your Mac\", @\"...this will fully remove LuLu from your Mac\"), @[NSLocalizedString(@\"Uninstall\", @\"Uninstall\"), NSLocalizedString(@\"Cancel\", @\"Cancel\")]);\n    \n    //cancel? ignore\n    if(NSAlertSecondButtonReturn == response)\n    {\n         //dbg msg\n         os_log_debug(logHandle, \"user canceled uninstalling\");\n         \n         //(re)background\n         [self setActivationPolicy];\n    }\n    //ok\n    // user wants to uninstall!\n    else\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"user confirmed uninstall\");\n        \n        //init\n        configure = [[Configure alloc] init];\n        \n        //quit\n        if(YES != [configure uninstall])\n        {\n            //err msg\n            os_log_error(logHandle, \"ERROR: uninstall failed\");\n        }\n        \n        //and terminate\n        [NSApplication.sharedApplication terminate:self];\n    }\n            \nbail:\n    \n    return;\n}\n\n\n@end\n"
  },
  {
    "path": "LuLu/App/Assets.xcassets/Ancestry.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"parents any.pdf\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"parents light.pdf\",\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"light\"\n        }\n      ]\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"parents dark.pdf\",\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"dark\"\n        }\n      ]\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  },\n  \"properties\" : {\n    \"template-rendering-intent\" : \"template\",\n    \"preserves-vector-representation\" : true\n  }\n}"
  },
  {
    "path": "LuLu/App/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"icon_16x16.png\",\n      \"idiom\" : \"mac\",\n      \"scale\" : \"1x\",\n      \"size\" : \"16x16\"\n    },\n    {\n      \"filename\" : \"icon_16x16@2x.png\",\n      \"idiom\" : \"mac\",\n      \"scale\" : \"2x\",\n      \"size\" : \"16x16\"\n    },\n    {\n      \"filename\" : \"icon_32x32.png\",\n      \"idiom\" : \"mac\",\n      \"scale\" : \"1x\",\n      \"size\" : \"32x32\"\n    },\n    {\n      \"filename\" : \"icon_32x32@2x.png\",\n      \"idiom\" : \"mac\",\n      \"scale\" : \"2x\",\n      \"size\" : \"32x32\"\n    },\n    {\n      \"filename\" : \"icon_128x128.png\",\n      \"idiom\" : \"mac\",\n      \"scale\" : \"1x\",\n      \"size\" : \"128x128\"\n    },\n    {\n      \"filename\" : \"icon_128x128@2x.png\",\n      \"idiom\" : \"mac\",\n      \"scale\" : \"2x\",\n      \"size\" : \"128x128\"\n    },\n    {\n      \"filename\" : \"icon_256x256.png\",\n      \"idiom\" : \"mac\",\n      \"scale\" : \"1x\",\n      \"size\" : \"256x256\"\n    },\n    {\n      \"filename\" : \"icon_256x256@2x.png\",\n      \"idiom\" : \"mac\",\n      \"scale\" : \"2x\",\n      \"size\" : \"256x256\"\n    },\n    {\n      \"filename\" : \"icon_512x512.png\",\n      \"idiom\" : \"mac\",\n      \"scale\" : \"1x\",\n      \"size\" : \"512x512\"\n    },\n    {\n      \"filename\" : \"icon_512x512@2x.png\",\n      \"idiom\" : \"mac\",\n      \"scale\" : \"2x\",\n      \"size\" : \"512x512\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "LuLu/App/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "LuLu/App/Assets.xcassets/FriendsFleet.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"darkMode.png\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"lightMode.png\",\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"light\"\n        }\n      ]\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"darkMode.png\",\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"dark\"\n        }\n      ]\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  },\n  \"properties\" : {\n    \"preserves-vector-representation\" : true\n  }\n}\n"
  },
  {
    "path": "LuLu/App/Assets.xcassets/FriendsHuntress.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"darkMode.png\",\n      \"idiom\" : \"mac\"\n    },\n    {\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"light\"\n        }\n      ],\n      \"filename\" : \"lightMode.png\",\n      \"idiom\" : \"mac\"\n    },\n    {\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"dark\"\n        }\n      ],\n      \"filename\" : \"darkMode.png\",\n      \"idiom\" : \"mac\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  },\n  \"properties\" : {\n    \"preserves-vector-representation\" : true\n  }\n}\n"
  },
  {
    "path": "LuLu/App/Assets.xcassets/FriendsJamf.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"darkMode.png\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"lightMode.png\",\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"light\"\n        }\n      ]\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"darkMode.png\",\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"dark\"\n        }\n      ]\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  },\n  \"properties\" : {\n    \"preserves-vector-representation\" : true\n  }\n}\n"
  },
  {
    "path": "LuLu/App/Assets.xcassets/FriendsKandji.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"darkMode.png\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"lightMode.png\",\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"light\"\n        }\n      ]\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"darkMode.png\",\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"dark\"\n        }\n      ]\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  },\n  \"properties\" : {\n    \"preserves-vector-representation\" : true\n  }\n}\n"
  },
  {
    "path": "LuLu/App/Assets.xcassets/FriendsMacPaw.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"darkMode.png\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"lightMode.png\",\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"light\"\n        }\n      ]\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"darkMode.png\",\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"dark\"\n        }\n      ]\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  },\n  \"properties\" : {\n    \"preserves-vector-representation\" : true\n  }\n}\n"
  },
  {
    "path": "LuLu/App/Assets.xcassets/FriendsMalwarebytes.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"logo.png\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  },\n  \"properties\" : {\n    \"preserves-vector-representation\" : true\n  }\n}\n"
  },
  {
    "path": "LuLu/App/Assets.xcassets/FriendsPANW.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"darkMode.png\",\n      \"idiom\" : \"mac\"\n    },\n    {\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"light\"\n        }\n      ],\n      \"filename\" : \"lightMode.png\",\n      \"idiom\" : \"mac\"\n    },\n    {\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"dark\"\n        }\n      ],\n      \"filename\" : \"darkMode.png\",\n      \"idiom\" : \"mac\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  },\n  \"properties\" : {\n    \"preserves-vector-representation\" : true\n  }\n}\n"
  },
  {
    "path": "LuLu/App/Assets.xcassets/FriendsSophos.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"sophos.png\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  },\n  \"properties\" : {\n    \"preserves-vector-representation\" : true\n  }\n}\n"
  },
  {
    "path": "LuLu/App/Assets.xcassets/FriendsiVerify.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"iVerify.png\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  },\n  \"properties\" : {\n    \"preserves-vector-representation\" : true\n  }\n}\n"
  },
  {
    "path": "LuLu/App/Assets.xcassets/Heart.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"heart_light-1.pdf\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"heart_light.pdf\",\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"light\"\n        }\n      ]\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"heart_dark.pdf\",\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"dark\"\n        }\n      ]\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  },\n  \"properties\" : {\n    \"preserves-vector-representation\" : true\n  }\n}"
  },
  {
    "path": "LuLu/App/Assets.xcassets/Icon.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"LoginItem Any.pdf\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"LoginItem Light.pdf\",\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"light\"\n        }\n      ]\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"LoginItem Dark.pdf\",\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"dark\"\n        }\n      ]\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  },\n  \"properties\" : {\n    \"preserves-vector-representation\" : true\n  }\n}"
  },
  {
    "path": "LuLu/App/Assets.xcassets/InstallAllow.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"allow.png\",\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"filename\" : \"allow_es.png\",\n      \"idiom\" : \"universal\",\n      \"locale\" : \"es\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"locale\" : \"es\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"locale\" : \"es\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"filename\" : \"allow_ko.png\",\n      \"idiom\" : \"universal\",\n      \"locale\" : \"ko\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"locale\" : \"ko\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"locale\" : \"ko\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  },\n  \"properties\" : {\n    \"localizable\" : true\n  }\n}\n"
  },
  {
    "path": "LuLu/App/Assets.xcassets/InstallApprove.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"approve.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"locale\" : \"es\",\n      \"idiom\" : \"universal\",\n      \"filename\" : \"approve_es.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"locale\" : \"es\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"locale\" : \"es\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"filename\" : \"approve_ko.png\",\n      \"idiom\" : \"universal\",\n      \"locale\" : \"ko\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"locale\" : \"ko\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"locale\" : \"ko\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  },\n  \"properties\" : {\n    \"localizable\" : true\n  }\n}"
  },
  {
    "path": "LuLu/App/Assets.xcassets/InstallApprove_OLD.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"approve.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"locale\" : \"es\",\n      \"idiom\" : \"universal\",\n      \"filename\" : \"approve_es.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"locale\" : \"es\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"locale\" : \"es\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  },\n  \"properties\" : {\n    \"localizable\" : true\n  }\n}"
  },
  {
    "path": "LuLu/App/Assets.xcassets/InstallAuth.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"auth.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"locale\" : \"es\",\n      \"idiom\" : \"universal\",\n      \"filename\" : \"auth_es.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"locale\" : \"es\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"locale\" : \"es\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"filename\" : \"auth_ko.png\",\n      \"idiom\" : \"universal\",\n      \"locale\" : \"ko\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"locale\" : \"ko\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"locale\" : \"ko\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  },\n  \"properties\" : {\n    \"localizable\" : true\n  }\n}"
  },
  {
    "path": "LuLu/App/Assets.xcassets/InstallBlocked.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"blocked.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"locale\" : \"es\",\n      \"idiom\" : \"universal\",\n      \"filename\" : \"blocked_es.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"locale\" : \"es\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"locale\" : \"es\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"filename\" : \"blocked_ko.png\",\n      \"idiom\" : \"universal\",\n      \"locale\" : \"ko\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"locale\" : \"ko\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"locale\" : \"ko\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  },\n  \"properties\" : {\n    \"localizable\" : true\n  }\n}"
  },
  {
    "path": "LuLu/App/Assets.xcassets/LuLuText.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"lulu_text.pdf\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"lulu_text-1.pdf\",\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"light\"\n        }\n      ]\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"lulu_text-2.pdf\",\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"dark\"\n        }\n      ]\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  },\n  \"properties\" : {\n    \"preserves-vector-representation\" : true\n  }\n}"
  },
  {
    "path": "LuLu/App/Assets.xcassets/PrefsList.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"icon.png\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"icon.png\",\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"light\"\n        }\n      ]\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"icon.png\",\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"dark\"\n        }\n      ]\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  },\n  \"properties\" : {\n    \"preserves-vector-representation\" : true\n  }\n}\n"
  },
  {
    "path": "LuLu/App/Assets.xcassets/PrefsMode.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"prefsMode Any.pdf\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"prefsMode Light.pdf\",\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"light\"\n        }\n      ]\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"prefsMode Dark.pdf\",\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"dark\"\n        }\n      ]\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  },\n  \"properties\" : {\n    \"preserves-vector-representation\" : true\n  }\n}"
  },
  {
    "path": "LuLu/App/Assets.xcassets/PrefsProfiles.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"light\"\n        }\n      ],\n      \"filename\" : \"profiles.png\",\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"dark\"\n        }\n      ],\n      \"filename\" : \"profilesDark.png\",\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"light\"\n        }\n      ],\n      \"filename\" : \"profiles@2x.png\",\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"dark\"\n        }\n      ],\n      \"filename\" : \"profilesDark@2x.png\",\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"light\"\n        }\n      ],\n      \"idiom\" : \"universal\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"dark\"\n        }\n      ],\n      \"idiom\" : \"universal\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "LuLu/App/Assets.xcassets/PrefsRules.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"prefsRules Any.pdf\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"prefsRules Light.pdf\",\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"light\"\n        }\n      ]\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"prefsRules Dark.pdf\",\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"dark\"\n        }\n      ]\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  },\n  \"properties\" : {\n    \"preserves-vector-representation\" : true\n  }\n}"
  },
  {
    "path": "LuLu/App/Assets.xcassets/PrefsUpdate.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"prefsUpdate Any.pdf\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"prefsUpdate Light.pdf\",\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"light\"\n        }\n      ]\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"prefsUpdate Dark.pdf\",\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"dark\"\n        }\n      ]\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  },\n  \"properties\" : {\n    \"preserves-vector-representation\" : true\n  }\n}"
  },
  {
    "path": "LuLu/App/Assets.xcassets/RulesAllow.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"rulesAllow Any.pdf\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"rulesAllow Light.pdf\",\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"light\"\n        }\n      ]\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"rulesAllow Dark.pdf\",\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"dark\"\n        }\n      ]\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  },\n  \"properties\" : {\n    \"preserves-vector-representation\" : true\n  }\n}"
  },
  {
    "path": "LuLu/App/Assets.xcassets/RulesBlock.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"block Any.pdf\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"block Light.pdf\",\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"light\"\n        }\n      ]\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"block Dark.pdf\",\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"dark\"\n        }\n      ]\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  },\n  \"properties\" : {\n    \"preserves-vector-representation\" : true\n  }\n}"
  },
  {
    "path": "LuLu/App/Assets.xcassets/RulesSystem.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"rulesSystem light.pdf\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"rulesSystem light-1.pdf\",\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"light\"\n        }\n      ]\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"rulesSystem dark.pdf\",\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"dark\"\n        }\n      ]\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  },\n  \"properties\" : {\n    \"preserves-vector-representation\" : true\n  }\n}"
  },
  {
    "path": "LuLu/App/Assets.xcassets/Signed.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"signed Any.pdf\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"signed Light.pdf\",\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"light\"\n        }\n      ]\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"signed Dark.pdf\",\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"dark\"\n        }\n      ]\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  },\n  \"properties\" : {\n    \"template-rendering-intent\" : \"template\",\n    \"preserves-vector-representation\" : true\n  }\n}"
  },
  {
    "path": "LuLu/App/Assets.xcassets/SignedApple.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"signedApple Any.pdf\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"signedApple Light.pdf\",\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"light\"\n        }\n      ]\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"signedApple Dark.pdf\",\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"dark\"\n        }\n      ]\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  },\n  \"properties\" : {\n    \"template-rendering-intent\" : \"template\",\n    \"preserves-vector-representation\" : true\n  }\n}"
  },
  {
    "path": "LuLu/App/Assets.xcassets/SignedUnknown.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"Unknown any.pdf\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"Unknown light.pdf\",\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"light\"\n        }\n      ]\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"Unknown dark.pdf\",\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"dark\"\n        }\n      ]\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  },\n  \"properties\" : {\n    \"template-rendering-intent\" : \"template\",\n    \"preserves-vector-representation\" : true\n  }\n}"
  },
  {
    "path": "LuLu/App/Assets.xcassets/StatusActive.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"LoginItem StatusBar Active.pdf\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  },\n  \"properties\" : {\n    \"template-rendering-intent\" : \"template\",\n    \"preserves-vector-representation\" : true\n  }\n}"
  },
  {
    "path": "LuLu/App/Assets.xcassets/StatusInactive.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"LoginItem StatusBar Inactive.pdf\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  },\n  \"properties\" : {\n    \"template-rendering-intent\" : \"template\",\n    \"preserves-vector-representation\" : true\n  }\n}"
  },
  {
    "path": "LuLu/App/Assets.xcassets/Unsigned.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"unsigned Any.pdf\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"unsigned Light.pdf\",\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"light\"\n        }\n      ]\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"unsigned Dark.pdf\",\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"dark\"\n        }\n      ]\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  },\n  \"properties\" : {\n    \"template-rendering-intent\" : \"template\",\n    \"preserves-vector-representation\" : true\n  }\n}"
  },
  {
    "path": "LuLu/App/Assets.xcassets/VTIcon.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"VT Light.pdf\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"VT Any-1.pdf\",\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"light\"\n        }\n      ]\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"VT Dark.pdf\",\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"dark\"\n        }\n      ]\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  },\n  \"properties\" : {\n    \"template-rendering-intent\" : \"template\",\n    \"preserves-vector-representation\" : true\n  }\n}"
  },
  {
    "path": "LuLu/App/Assets.xcassets/allow.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"rulesAllow Any.pdf\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"rulesAllow Light.pdf\",\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"light\"\n        }\n      ]\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"rulesAllow Dark.pdf\",\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"dark\"\n        }\n      ]\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  },\n  \"properties\" : {\n    \"preserves-vector-representation\" : true\n  }\n}"
  },
  {
    "path": "LuLu/App/Assets.xcassets/block.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"block Any.pdf\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"block Light.pdf\",\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"light\"\n        }\n      ]\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"block Dark.pdf\",\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"dark\"\n        }\n      ]\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  },\n  \"properties\" : {\n    \"preserves-vector-representation\" : true\n  }\n}"
  },
  {
    "path": "LuLu/App/Assets.xcassets/refresh.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"refresh.png\",\n      \"idiom\" : \"mac\"\n    },\n    {\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"light\"\n        }\n      ],\n      \"filename\" : \"refresh.png\",\n      \"idiom\" : \"mac\"\n    },\n    {\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"dark\"\n        }\n      ],\n      \"filename\" : \"refresh.png\",\n      \"idiom\" : \"mac\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  },\n  \"properties\" : {\n    \"preserves-vector-representation\" : true\n  }\n}\n"
  },
  {
    "path": "LuLu/App/Assets.xcassets/rulesRecent.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"rulesRecent.png\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"rulesRecent.png\",\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"light\"\n        }\n      ]\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"rulesRecent.png\",\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"dark\"\n        }\n      ]\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  },\n  \"properties\" : {\n    \"preserves-vector-representation\" : true\n  }\n}\n"
  },
  {
    "path": "LuLu/App/Assets.xcassets/rulesUnknown.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"rulesUnknown.png\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"rulesUnknown.png\",\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"light\"\n        }\n      ]\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"filename\" : \"rulesUnknown.png\",\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"dark\"\n        }\n      ]\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  },\n  \"properties\" : {\n    \"preserves-vector-representation\" : true\n  }\n}\n"
  },
  {
    "path": "LuLu/App/Base.lproj/AboutWindow.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"23727\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"23727\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"AboutWindowController\">\n            <connections>\n                <outlet property=\"patrons\" destination=\"j2X-Ub-niY\" id=\"gfG-o9-RbL\"/>\n                <outlet property=\"versionLabel\" destination=\"OSm-xS-Dmd\" id=\"luW-4O-fYe\"/>\n                <outlet property=\"window\" destination=\"F0z-JX-Cv5\" id=\"gIp-Ho-8D9\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <window allowsToolTipsWhenApplicationIsInactive=\"NO\" autorecalculatesKeyViewLoop=\"NO\" releasedWhenClosed=\"NO\" animationBehavior=\"default\" id=\"F0z-JX-Cv5\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\" closable=\"YES\" texturedBackground=\"YES\"/>\n            <rect key=\"contentRect\" x=\"196\" y=\"240\" width=\"486\" height=\"301\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"3440\" height=\"1415\"/>\n            <view key=\"contentView\" id=\"se5-gp-TjO\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"486\" height=\"301\"/>\n                <autoresizingMask key=\"autoresizingMask\"/>\n                <subviews>\n                    <imageView horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"lEv-Wj-6S5\">\n                        <rect key=\"frame\" x=\"10\" y=\"190\" width=\"110\" height=\"106\"/>\n                        <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                        <imageCell key=\"cell\" refusesFirstResponder=\"YES\" alignment=\"left\" imageScaling=\"proportionallyDown\" image=\"Icon\" id=\"xKf-GK-m0k\"/>\n                    </imageView>\n                    <imageView horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Eaf-yA-bbe\">\n                        <rect key=\"frame\" x=\"158\" y=\"231\" width=\"116\" height=\"50\"/>\n                        <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                        <imageCell key=\"cell\" refusesFirstResponder=\"YES\" alignment=\"left\" imageScaling=\"proportionallyDown\" image=\"LuLuText\" id=\"Ws8-bD-j2R\"/>\n                    </imageView>\n                    <button tag=\"101\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"HZZ-Es-mpy\">\n                        <rect key=\"frame\" x=\"13\" y=\"13\" width=\"165\" height=\"32\"/>\n                        <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"More Information\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"J9x-sM-h9S\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" size=\"13\" name=\"Menlo-Regular\"/>\n                        </buttonCell>\n                        <connections>\n                            <action selector=\"buttonHandler:\" target=\"-2\" id=\"Cgx-f4-Thr\"/>\n                        </connections>\n                    </button>\n                    <scrollView fixedFrame=\"YES\" horizontalLineScroll=\"10\" horizontalPageScroll=\"10\" verticalLineScroll=\"10\" verticalPageScroll=\"10\" hasHorizontalScroller=\"NO\" usesPredominantAxisScrolling=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"5if-J7-OZf\">\n                        <rect key=\"frame\" x=\"20\" y=\"68\" width=\"446\" height=\"97\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                        <clipView key=\"contentView\" drawsBackground=\"NO\" id=\"WiG-CC-JV3\">\n                            <rect key=\"frame\" x=\"1\" y=\"1\" width=\"444\" height=\"95\"/>\n                            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                            <subviews>\n                                <textView editable=\"NO\" importsGraphics=\"NO\" verticallyResizable=\"YES\" usesFontPanel=\"YES\" findStyle=\"panel\" continuousSpellChecking=\"YES\" allowsUndo=\"YES\" usesRuler=\"YES\" allowsNonContiguousLayout=\"YES\" quoteSubstitution=\"YES\" dashSubstitution=\"YES\" spellingCorrection=\"YES\" smartInsertDelete=\"YES\" id=\"j2X-Ub-niY\">\n                                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"444\" height=\"95\"/>\n                                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                    <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <size key=\"minSize\" width=\"444\" height=\"95\"/>\n                                    <size key=\"maxSize\" width=\"463\" height=\"10000000\"/>\n                                    <attributedString key=\"textStorage\">\n                                        <fragment content=\"list here...\">\n                                            <attributes>\n                                                <color key=\"NSColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <font key=\"NSFont\" size=\"13\" name=\"Menlo-Regular\"/>\n                                                <paragraphStyle key=\"NSParagraphStyle\" alignment=\"natural\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\"/>\n                                            </attributes>\n                                        </fragment>\n                                    </attributedString>\n                                    <color key=\"insertionPointColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textView>\n                            </subviews>\n                        </clipView>\n                        <scroller key=\"horizontalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" doubleValue=\"1\" horizontal=\"YES\" id=\"iNL-vM-cLm\">\n                            <rect key=\"frame\" x=\"-100\" y=\"-100\" width=\"87\" height=\"18\"/>\n                            <autoresizingMask key=\"autoresizingMask\"/>\n                        </scroller>\n                        <scroller key=\"verticalScroller\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" doubleValue=\"1\" horizontal=\"NO\" id=\"6bw-3O-hPc\">\n                            <rect key=\"frame\" x=\"429\" y=\"1\" width=\"16\" height=\"95\"/>\n                            <autoresizingMask key=\"autoresizingMask\"/>\n                        </scroller>\n                    </scrollView>\n                    <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"fZJ-sG-ZuJ\">\n                        <rect key=\"frame\" x=\"20\" y=\"166\" width=\"447\" height=\"19\"/>\n                        <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Patrons &amp; Friends\" id=\"fJg-qw-wDf\">\n                            <font key=\"font\" size=\"13\" name=\"Menlo-Regular\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" allowsCharacterPickerTouchBarItem=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"OSm-xS-Dmd\">\n                        <rect key=\"frame\" x=\"158\" y=\"217\" width=\"182\" height=\"19\"/>\n                        <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Version:\" id=\"bBK-v0-ypq\">\n                            <font key=\"font\" size=\"13\" name=\"Menlo-Regular\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <button tag=\"100\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"xnd-Gw-0o8\">\n                        <rect key=\"frame\" x=\"308\" y=\"13\" width=\"165\" height=\"32\"/>\n                        <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Support Us!\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"6g3-Pg-x3P\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" size=\"13\" name=\"Menlo-Regular\"/>\n                        </buttonCell>\n                        <connections>\n                            <action selector=\"buttonHandler:\" target=\"-2\" id=\"gP0-s7-o6h\"/>\n                        </connections>\n                    </button>\n                </subviews>\n            </view>\n            <connections>\n                <outlet property=\"delegate\" destination=\"-2\" id=\"0bl-1N-AYu\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"350\" y=\"335.5\"/>\n        </window>\n    </objects>\n    <resources>\n        <image name=\"Icon\" width=\"144\" height=\"144\"/>\n        <image name=\"LuLuText\" width=\"1268\" height=\"385\"/>\n    </resources>\n</document>\n"
  },
  {
    "path": "LuLu/App/Base.lproj/AddRule.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"24128\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"24128\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"AddRuleWindowController\">\n            <connections>\n                <outlet property=\"addButton\" destination=\"XX0-l9-AZe\" id=\"I68-1X-bav\"/>\n                <outlet property=\"allowButton\" destination=\"LyI-TV-Syi\" id=\"oVm-9P-98o\"/>\n                <outlet property=\"blockButton\" destination=\"FGP-wa-tQy\" id=\"kO9-Qb-tef\"/>\n                <outlet property=\"endpointAddr\" destination=\"6aQ-uZ-MQT\" id=\"ksf-G1-hEj\"/>\n                <outlet property=\"endpointPort\" destination=\"SsU-Va-Vcn\" id=\"0pF-sT-O1X\"/>\n                <outlet property=\"icon\" destination=\"Z5k-JM-ou9\" id=\"Tt0-DT-cDR\"/>\n                <outlet property=\"isEndpointAddrRegex\" destination=\"AdX-rG-UUh\" id=\"JJu-54-veK\"/>\n                <outlet property=\"path\" destination=\"TMj-aG-iTU\" id=\"tz6-F4-QBt\"/>\n                <outlet property=\"window\" destination=\"F0z-JX-Cv5\" id=\"gIp-Ho-8D9\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <window title=\"Add Rule (for outgoing connections)\" allowsToolTipsWhenApplicationIsInactive=\"NO\" autorecalculatesKeyViewLoop=\"NO\" releasedWhenClosed=\"NO\" visibleAtLaunch=\"NO\" animationBehavior=\"default\" id=\"F0z-JX-Cv5\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\" closable=\"YES\" resizable=\"YES\"/>\n            <rect key=\"contentRect\" x=\"196\" y=\"240\" width=\"508\" height=\"325\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"3440\" height=\"1410\"/>\n            <value key=\"minSize\" type=\"size\" width=\"508\" height=\"325\"/>\n            <value key=\"maxSize\" type=\"size\" width=\"800\" height=\"325\"/>\n            <view key=\"contentView\" id=\"se5-gp-TjO\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"508\" height=\"325\"/>\n                <autoresizingMask key=\"autoresizingMask\"/>\n                <subviews>\n                    <button ambiguous=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"FGP-wa-tQy\">\n                        <rect key=\"frame\" x=\"103\" y=\"52\" width=\"69\" height=\"16\"/>\n                        <buttonCell key=\"cell\" type=\"radio\" title=\" Block\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" state=\"on\" inset=\"2\" id=\"JJl-Lz-apr\">\n                            <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                            <font key=\"font\" size=\"13\" name=\"Menlo-Regular\"/>\n                        </buttonCell>\n                        <connections>\n                            <action selector=\"radioButtonsHandler:\" target=\"-2\" id=\"liR-62-kN9\"/>\n                        </connections>\n                    </button>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ZX5-FR-Ua8\">\n                        <rect key=\"frame\" x=\"402\" y=\"219\" width=\"86\" height=\"21\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Browse\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"OoX-aE-Hgf\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" size=\"13\" name=\"Menlo-Regular\"/>\n                        </buttonCell>\n                        <constraints>\n                            <constraint firstAttribute=\"height\" constant=\"21\" id=\"2tj-XI-LkF\"/>\n                            <constraint firstAttribute=\"width\" constant=\"86\" id=\"kBa-5d-iLO\"/>\n                        </constraints>\n                        <connections>\n                            <action selector=\"browseButtonHandler:\" target=\"-2\" id=\"PT1-Ty-Np7\"/>\n                        </connections>\n                    </button>\n                    <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"TMj-aG-iTU\">\n                        <rect key=\"frame\" x=\"103\" y=\"248\" width=\"385\" height=\"24\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"height\" constant=\"24\" id=\"mOR-Su-gK2\"/>\n                        </constraints>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" drawsBackground=\"YES\" id=\"Bon-iR-8FO\">\n                            <font key=\"font\" size=\"13\" name=\"Menlo-Regular\"/>\n                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"lP5-by-JA2\">\n                        <rect key=\"frame\" x=\"101\" y=\"272\" width=\"389\" height=\"17\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"height\" constant=\"17\" id=\"FPl-4Y-c6j\"/>\n                            <constraint firstAttribute=\"width\" constant=\"385\" id=\"XgJ-Ba-s1A\"/>\n                        </constraints>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Program path\" id=\"tc1-pS-Wns\">\n                            <font key=\"font\" size=\"13\" name=\"Menlo-Regular\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"6aQ-uZ-MQT\">\n                        <rect key=\"frame\" x=\"103\" y=\"138\" width=\"385\" height=\"24\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"height\" constant=\"24\" id=\"azV-rq-4Id\"/>\n                        </constraints>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" placeholderString=\"*\" drawsBackground=\"YES\" id=\"QWe-2U-lfn\">\n                            <font key=\"font\" size=\"13\" name=\"Menlo-Regular\"/>\n                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"751\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"wLJ-6S-WeA\">\n                        <rect key=\"frame\" x=\"101\" y=\"167\" width=\"169\" height=\"15\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Remote address/domain\" id=\"7yf-wW-FZC\">\n                            <font key=\"font\" size=\"13\" name=\"Menlo-Regular\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"SsU-Va-Vcn\">\n                        <rect key=\"frame\" x=\"103\" y=\"84\" width=\"385\" height=\"24\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"height\" constant=\"24\" id=\"rzM-Fb-Vh0\"/>\n                        </constraints>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" placeholderString=\"*\" drawsBackground=\"YES\" id=\"kXW-Xv-Fc4\">\n                            <font key=\"font\" size=\"13\" name=\"Menlo-Regular\"/>\n                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"3qP-ad-9Fq\">\n                        <rect key=\"frame\" x=\"101\" y=\"108\" width=\"389\" height=\"17\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"width\" constant=\"385\" id=\"jwv-kR-E8V\"/>\n                            <constraint firstAttribute=\"height\" constant=\"17\" id=\"o6F-EB-EIp\"/>\n                        </constraints>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Remote port\" id=\"5ic-Om-d8g\">\n                            <font key=\"font\" size=\"13\" name=\"Menlo-Regular\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <imageView horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Z5k-JM-ou9\">\n                        <rect key=\"frame\" x=\"20\" y=\"228\" width=\"66\" height=\"64\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"height\" constant=\"64\" id=\"4sh-vk-SxP\"/>\n                            <constraint firstAttribute=\"width\" constant=\"66\" id=\"Swd-b7-aKa\"/>\n                        </constraints>\n                        <imageCell key=\"cell\" refusesFirstResponder=\"YES\" alignment=\"left\" imageScaling=\"proportionallyUpOrDown\" id=\"h8l-JG-MHD\"/>\n                    </imageView>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Rer-xE-vmi\">\n                        <rect key=\"frame\" x=\"294\" y=\"20\" width=\"86\" height=\"21\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Cancel\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"fX0-Jq-Okq\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" size=\"13\" name=\"Menlo-Regular\"/>\n                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nGw\n</string>\n                        </buttonCell>\n                        <constraints>\n                            <constraint firstAttribute=\"width\" constant=\"86\" id=\"4xU-ew-nvK\"/>\n                            <constraint firstAttribute=\"height\" constant=\"21\" id=\"ret-kW-s6x\"/>\n                        </constraints>\n                        <connections>\n                            <action selector=\"cancelButtonHandler:\" target=\"-2\" id=\"Fws-JZ-RMQ\"/>\n                        </connections>\n                    </button>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"XX0-l9-AZe\">\n                        <rect key=\"frame\" x=\"402\" y=\"20\" width=\"86\" height=\"21\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Add\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"V5P-DF-wCP\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" size=\"13\" name=\"Menlo-Bold\"/>\n                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nGw\n</string>\n                        </buttonCell>\n                        <constraints>\n                            <constraint firstAttribute=\"width\" constant=\"86\" id=\"L0j-xG-Jk9\"/>\n                            <constraint firstAttribute=\"height\" constant=\"21\" id=\"Pno-Yh-Pt3\"/>\n                        </constraints>\n                        <connections>\n                            <action selector=\"addButtonHandler:\" target=\"-2\" id=\"aca-Io-ckN\"/>\n                        </connections>\n                    </button>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"AdX-rG-UUh\">\n                        <rect key=\"frame\" x=\"281\" y=\"167\" width=\"65\" height=\"15\"/>\n                        <buttonCell key=\"cell\" type=\"check\" title=\"regex?\" bezelStyle=\"regularSquare\" imagePosition=\"left\" controlSize=\"small\" scrollable=\"YES\" lineBreakMode=\"clipping\" inset=\"2\" id=\"FCA-Cv-yT3\">\n                            <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                            <font key=\"font\" size=\"13\" name=\"Menlo-Regular\"/>\n                        </buttonCell>\n                    </button>\n                    <button tag=\"1\" ambiguous=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"LyI-TV-Syi\">\n                        <rect key=\"frame\" x=\"188\" y=\"52\" width=\"69\" height=\"16\"/>\n                        <buttonCell key=\"cell\" type=\"radio\" title=\" Allow\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"oCK-aR-Ek4\">\n                            <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                            <font key=\"font\" size=\"13\" name=\"Menlo-Regular\"/>\n                        </buttonCell>\n                        <connections>\n                            <action selector=\"radioButtonsHandler:\" target=\"-2\" id=\"Si1-r7-F3A\"/>\n                        </connections>\n                    </button>\n                </subviews>\n                <constraints>\n                    <constraint firstItem=\"6aQ-uZ-MQT\" firstAttribute=\"leading\" secondItem=\"se5-gp-TjO\" secondAttribute=\"leading\" constant=\"103\" id=\"1jf-Ef-7vq\"/>\n                    <constraint firstItem=\"FGP-wa-tQy\" firstAttribute=\"leading\" secondItem=\"se5-gp-TjO\" secondAttribute=\"leading\" constant=\"103\" id=\"2mc-m2-eFc\"/>\n                    <constraint firstItem=\"3qP-ad-9Fq\" firstAttribute=\"top\" secondItem=\"se5-gp-TjO\" secondAttribute=\"top\" constant=\"200\" id=\"3nW-ko-4GU\"/>\n                    <constraint firstItem=\"AdX-rG-UUh\" firstAttribute=\"top\" secondItem=\"se5-gp-TjO\" secondAttribute=\"top\" constant=\"143\" id=\"8r9-wl-qej\"/>\n                    <constraint firstItem=\"6aQ-uZ-MQT\" firstAttribute=\"top\" secondItem=\"se5-gp-TjO\" secondAttribute=\"top\" constant=\"163\" id=\"9lb-LS-1f3\"/>\n                    <constraint firstItem=\"Z5k-JM-ou9\" firstAttribute=\"leading\" secondItem=\"se5-gp-TjO\" secondAttribute=\"leading\" constant=\"20\" id=\"Bsm-eQ-WBT\"/>\n                    <constraint firstItem=\"Z5k-JM-ou9\" firstAttribute=\"top\" secondItem=\"se5-gp-TjO\" secondAttribute=\"top\" constant=\"33\" id=\"DDj-SN-vYJ\"/>\n                    <constraint firstItem=\"wLJ-6S-WeA\" firstAttribute=\"leading\" secondItem=\"se5-gp-TjO\" secondAttribute=\"leading\" constant=\"103\" id=\"EVc-Xa-4Xc\"/>\n                    <constraint firstItem=\"ZX5-FR-Ua8\" firstAttribute=\"top\" secondItem=\"TMj-aG-iTU\" secondAttribute=\"bottom\" constant=\"8\" id=\"G0s-dZ-cD4\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"TMj-aG-iTU\" secondAttribute=\"trailing\" constant=\"20\" id=\"GRZ-S9-nJ5\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"6aQ-uZ-MQT\" secondAttribute=\"trailing\" constant=\"20\" id=\"J7N-Ca-drt\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"SsU-Va-Vcn\" secondAttribute=\"trailing\" constant=\"20\" id=\"Okk-id-3l5\"/>\n                    <constraint firstItem=\"LyI-TV-Syi\" firstAttribute=\"leading\" secondItem=\"FGP-wa-tQy\" secondAttribute=\"trailing\" constant=\"16\" id=\"Oz3-4w-4NS\"/>\n                    <constraint firstItem=\"wLJ-6S-WeA\" firstAttribute=\"top\" secondItem=\"se5-gp-TjO\" secondAttribute=\"top\" constant=\"143\" id=\"VvY-5T-5g7\"/>\n                    <constraint firstItem=\"SsU-Va-Vcn\" firstAttribute=\"leading\" secondItem=\"se5-gp-TjO\" secondAttribute=\"leading\" constant=\"103\" id=\"YjJ-dJ-sL6\"/>\n                    <constraint firstItem=\"TMj-aG-iTU\" firstAttribute=\"leading\" secondItem=\"Z5k-JM-ou9\" secondAttribute=\"trailing\" constant=\"17\" id=\"cFA-dk-4v5\"/>\n                    <constraint firstItem=\"3qP-ad-9Fq\" firstAttribute=\"leading\" secondItem=\"se5-gp-TjO\" secondAttribute=\"leading\" constant=\"103\" id=\"dhM-Ur-ySU\"/>\n                    <constraint firstItem=\"lP5-by-JA2\" firstAttribute=\"leading\" secondItem=\"Z5k-JM-ou9\" secondAttribute=\"trailing\" constant=\"17\" id=\"e9P-Va-2jR\"/>\n                    <constraint firstItem=\"TMj-aG-iTU\" firstAttribute=\"top\" secondItem=\"lP5-by-JA2\" secondAttribute=\"bottom\" id=\"hS0-ei-rsR\"/>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"Rer-xE-vmi\" secondAttribute=\"bottom\" constant=\"20\" id=\"jnx-vr-7F5\"/>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"XX0-l9-AZe\" secondAttribute=\"bottom\" constant=\"20\" id=\"laB-iV-gzu\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"ZX5-FR-Ua8\" secondAttribute=\"trailing\" constant=\"20\" id=\"o1Z-5c-UnM\"/>\n                    <constraint firstItem=\"SsU-Va-Vcn\" firstAttribute=\"top\" secondItem=\"3qP-ad-9Fq\" secondAttribute=\"bottom\" id=\"qNc-5S-RhQ\"/>\n                    <constraint firstItem=\"lP5-by-JA2\" firstAttribute=\"top\" secondItem=\"se5-gp-TjO\" secondAttribute=\"top\" constant=\"36\" id=\"qv3-Nt-0qN\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"XX0-l9-AZe\" secondAttribute=\"trailing\" constant=\"20\" id=\"qzI-8A-AIe\"/>\n                    <constraint firstItem=\"AdX-rG-UUh\" firstAttribute=\"leading\" secondItem=\"wLJ-6S-WeA\" secondAttribute=\"trailing\" constant=\"13\" id=\"uTM-gY-m6s\"/>\n                    <constraint firstItem=\"XX0-l9-AZe\" firstAttribute=\"leading\" secondItem=\"Rer-xE-vmi\" secondAttribute=\"trailing\" constant=\"22\" id=\"xjF-Lb-cnT\"/>\n                </constraints>\n            </view>\n            <connections>\n                <outlet property=\"delegate\" destination=\"-2\" id=\"0bl-1N-AYu\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"154\" y=\"188.5\"/>\n        </window>\n    </objects>\n</document>\n"
  },
  {
    "path": "LuLu/App/Base.lproj/AlertWindow.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"24128\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"24128\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"AlertWindowController\">\n            <connections>\n                <outlet property=\"actionScope\" destination=\"TSg-6a-DVi\" id=\"ScH-Wk-QmL\"/>\n                <outlet property=\"alertMessage\" destination=\"HWR-Ex-H2f\" id=\"1p4-Ju-Y8P\"/>\n                <outlet property=\"allowButton\" destination=\"yg5-Dg-d1n\" id=\"cc0-x6-Fb4\"/>\n                <outlet property=\"ancestryButton\" destination=\"32G-48-5jq\" id=\"7ng-Oo-qJS\"/>\n                <outlet property=\"ancestryOutline\" destination=\"1Kj-Rh-cPo\" id=\"aWT-E0-V77\"/>\n                <outlet property=\"ancestryPopover\" destination=\"25r-fL-QMB\" id=\"7Fk-dG-0ME\"/>\n                <outlet property=\"ancestryTextCell\" destination=\"9sX-aC-eeQ\" id=\"YUy-If-CGd\"/>\n                <outlet property=\"ancestryView\" destination=\"Kwa-G9-AmS\" id=\"t8F-9N-ZWL\"/>\n                <outlet property=\"ancestryViewController\" destination=\"7sP-aX-0Jo\" id=\"Ivg-e4-CP3\"/>\n                <outlet property=\"ipAddress\" destination=\"0yy-0X-fb5\" id=\"3oB-wP-kb8\"/>\n                <outlet property=\"options\" destination=\"xge-2z-T9l\" id=\"o5W-uL-UdB\"/>\n                <outlet property=\"portProto\" destination=\"5Lz-xv-ErN\" id=\"9GP-2B-1ki\"/>\n                <outlet property=\"processArgs\" destination=\"ndx-hj-9e4\" id=\"LMk-Ad-2I4\"/>\n                <outlet property=\"processID\" destination=\"Nf4-ZN-jcK\" id=\"rWg-or-ZRT\"/>\n                <outlet property=\"processIcon\" destination=\"fJv-Iu-3gy\" id=\"T6F-QS-Nvk\"/>\n                <outlet property=\"processName\" destination=\"i1i-s4-Q02\" id=\"6qK-Sy-fuG\"/>\n                <outlet property=\"processPath\" destination=\"Jci-ZZ-1Ro\" id=\"BPX-tC-0fb\"/>\n                <outlet property=\"reverseDNS\" destination=\"BQn-nb-yUE\" id=\"4hZ-5J-YhR\"/>\n                <outlet property=\"ruleDurationAlways\" destination=\"n0b-XP-ZUr\" id=\"jmT-9a-gCW\"/>\n                <outlet property=\"ruleDurationCustom\" destination=\"Xf4-RL-C1a\" id=\"jZh-xe-ARc\"/>\n                <outlet property=\"ruleDurationHours\" destination=\"hbn-rf-Xhf\" id=\"WDD-zX-0W5\"/>\n                <outlet property=\"ruleDurationMinutes\" destination=\"yCo-33-DDd\" id=\"BYS-XV-Vt6\"/>\n                <outlet property=\"ruleDurationProcess\" destination=\"FV9-wU-TBa\" id=\"yUN-2u-Qlm\"/>\n                <outlet property=\"showOptions\" destination=\"QJt-zQ-EMG\" id=\"e6f-Ko-bu3\"/>\n                <outlet property=\"signingInfoButton\" destination=\"FqM-TW-r0o\" id=\"rKm-F3-llh\"/>\n                <outlet property=\"signingInfoPopover\" destination=\"Vmt-MD-3aB\" id=\"j62-vV-hvI\"/>\n                <outlet property=\"timeStamp\" destination=\"qWw-SE-uh0\" id=\"9XD-1e-EJI\"/>\n                <outlet property=\"virusTotalButton\" destination=\"PJQ-Iq-93l\" id=\"S5x-rJ-XJD\"/>\n                <outlet property=\"virusTotalPopover\" destination=\"jsE-Vn-PhK\" id=\"uMq-2j-5rE\"/>\n                <outlet property=\"window\" destination=\"F0z-JX-Cv5\" id=\"gIp-Ho-8D9\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <window identifier=\"Alert\" title=\"LuLu Alert\" allowsToolTipsWhenApplicationIsInactive=\"NO\" autorecalculatesKeyViewLoop=\"NO\" releasedWhenClosed=\"NO\" visibleAtLaunch=\"NO\" animationBehavior=\"default\" id=\"F0z-JX-Cv5\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\" resizable=\"YES\"/>\n            <rect key=\"contentRect\" x=\"949\" y=\"509\" width=\"667\" height=\"452\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"1280\" height=\"770\"/>\n            <value key=\"minSize\" type=\"size\" width=\"745\" height=\"244\"/>\n            <value key=\"maxSize\" type=\"size\" width=\"1337\" height=\"582\"/>\n            <view key=\"contentView\" wantsLayer=\"YES\" id=\"se5-gp-TjO\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"667\" height=\"452\"/>\n                <autoresizingMask key=\"autoresizingMask\"/>\n                <subviews>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"FqM-TW-r0o\" userLabel=\"Signing Info\">\n                        <rect key=\"frame\" x=\"26\" y=\"252\" width=\"37\" height=\"43\"/>\n                        <buttonCell key=\"cell\" type=\"bevel\" bezelStyle=\"rounded\" image=\"Signed\" imagePosition=\"only\" alignment=\"center\" imageScaling=\"proportionallyUpOrDown\" inset=\"2\" id=\"jqN-df-6uA\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" changeContents=\"YES\" lightByContents=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                        </buttonCell>\n                        <constraints>\n                            <constraint firstAttribute=\"width\" constant=\"37\" id=\"cxX-UP-eNr\"/>\n                            <constraint firstAttribute=\"height\" constant=\"43\" id=\"t2h-ly-aa9\"/>\n                        </constraints>\n                        <connections>\n                            <action selector=\"signingInfoButtonHandler:\" target=\"-2\" id=\"wdK-FI-wn5\"/>\n                        </connections>\n                    </button>\n                    <button horizontalHuggingPriority=\"750\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"QJt-zQ-EMG\">\n                        <rect key=\"frame\" x=\"29\" y=\"222\" width=\"13\" height=\"13\"/>\n                        <buttonCell key=\"cell\" type=\"disclosureTriangle\" bezelStyle=\"disclosure\" imagePosition=\"only\" alignment=\"left\" controlSize=\"large\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"eTb-0U-yh9\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" changeBackground=\"YES\" changeGray=\"YES\" lightByContents=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                        </buttonCell>\n                        <connections>\n                            <action selector=\"toggleOptionsView:\" target=\"-2\" id=\"zZi-4N-YkL\"/>\n                        </connections>\n                    </button>\n                    <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" allowsCharacterPickerTouchBarItem=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"tWx-6z-uXa\">\n                        <rect key=\"frame\" x=\"43\" y=\"221\" width=\"296\" height=\"15\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"height\" constant=\"15\" id=\"JbN-x8-MlU\"/>\n                            <constraint firstAttribute=\"width\" constant=\"292\" id=\"NrD-pm-grO\"/>\n                        </constraints>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Details &amp; Options\" id=\"FYF-6N-pro\">\n                            <font key=\"font\" size=\"13\" name=\"Menlo-Regular\"/>\n                            <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <button tag=\"102\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"32G-48-5jq\" userLabel=\"ancestryButton\">\n                        <rect key=\"frame\" x=\"79\" y=\"252\" width=\"37\" height=\"37\"/>\n                        <buttonCell key=\"cell\" type=\"bevel\" bezelStyle=\"regularSquare\" image=\"Ancestry\" imagePosition=\"only\" alignment=\"center\" imageScaling=\"axesIndependently\" inset=\"2\" id=\"WFc-i8-hne\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" changeContents=\"YES\" lightByContents=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                        </buttonCell>\n                        <constraints>\n                            <constraint firstAttribute=\"height\" constant=\"37\" id=\"DUe-bV-VqQ\"/>\n                            <constraint firstAttribute=\"width\" constant=\"37\" id=\"ZVl-sm-7bC\"/>\n                        </constraints>\n                        <connections>\n                            <action selector=\"ancestryButtonHandler:\" target=\"-2\" id=\"swJ-GY-xR7\"/>\n                        </connections>\n                    </button>\n                    <button tag=\"101\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"PJQ-Iq-93l\" userLabel=\"virusTotalButton\">\n                        <rect key=\"frame\" x=\"134\" y=\"258\" width=\"31\" height=\"28\"/>\n                        <buttonCell key=\"cell\" type=\"bevel\" bezelStyle=\"regularSquare\" image=\"VTIcon\" imagePosition=\"only\" alignment=\"center\" imageScaling=\"axesIndependently\" inset=\"2\" id=\"8lj-Ke-Kyw\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" changeContents=\"YES\" lightByContents=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                        </buttonCell>\n                        <constraints>\n                            <constraint firstAttribute=\"height\" constant=\"28\" id=\"blO-ys-XS5\"/>\n                            <constraint firstAttribute=\"width\" constant=\"31\" id=\"m1o-zM-X6Y\"/>\n                        </constraints>\n                        <connections>\n                            <action selector=\"vtButtonHandler:\" target=\"-2\" id=\"Skx-8d-U7n\"/>\n                        </connections>\n                    </button>\n                    <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" allowsCharacterPickerTouchBarItem=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"i1i-s4-Q02\">\n                        <rect key=\"frame\" x=\"174\" y=\"387\" width=\"475\" height=\"26\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"height\" constant=\"26\" id=\"TlQ-zK-g5h\"/>\n                        </constraints>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" truncatesLastVisibleLine=\"YES\" selectable=\"YES\" allowsUndo=\"NO\" sendsActionOnEndEditing=\"YES\" title=\"Process Name\" id=\"JEi-1U-vkU\">\n                            <font key=\"font\" size=\"23\" name=\"Menlo-Bold\"/>\n                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Aix-a5-CPT\">\n                        <rect key=\"frame\" x=\"340\" y=\"253\" width=\"135\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Block\" bezelStyle=\"rounded\" alignment=\"center\" controlSize=\"large\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"W18-Ba-X7J\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" size=\"15\" name=\"Menlo-Bold\"/>\n                        </buttonCell>\n                        <constraints>\n                            <constraint firstAttribute=\"height\" constant=\"32\" id=\"ExL-7P-xXi\"/>\n                            <constraint firstAttribute=\"width\" constant=\"135\" id=\"PSu-sb-mSm\"/>\n                        </constraints>\n                        <connections>\n                            <action selector=\"handleUserResponse:\" target=\"-2\" id=\"M1m-yw-PMX\"/>\n                        </connections>\n                    </button>\n                    <customView id=\"xge-2z-T9l\" userLabel=\"Options View\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"667\" height=\"214\"/>\n                        <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                        <subviews>\n                            <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" ambiguous=\"YES\" allowsCharacterPickerTouchBarItem=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"3UE-gu-DMS\">\n                                <rect key=\"frame\" x=\"26\" y=\"172\" width=\"61\" height=\"13\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"height\" constant=\"13\" id=\"3d2-xL-uK6\"/>\n                                    <constraint firstAttribute=\"width\" constant=\"116\" id=\"EQY-yh-HwX\"/>\n                                </constraints>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"pid:\" id=\"HZu-Op-XHi\">\n                                    <font key=\"font\" size=\"10\" name=\"Menlo-Regular\"/>\n                                    <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                            <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" ambiguous=\"YES\" allowsCharacterPickerTouchBarItem=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"0KC-Qa-4MU\">\n                                <rect key=\"frame\" x=\"26\" y=\"155\" width=\"61\" height=\"13\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"height\" constant=\"13\" id=\"2uJ-qs-d2A\"/>\n                                    <constraint firstAttribute=\"width\" constant=\"116\" id=\"725-wI-vXi\"/>\n                                </constraints>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"args:\" id=\"T20-eE-vRR\">\n                                    <font key=\"font\" size=\"10\" name=\"Menlo-Regular\"/>\n                                    <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                            <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" ambiguous=\"YES\" allowsCharacterPickerTouchBarItem=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"B2m-tX-bhM\">\n                                <rect key=\"frame\" x=\"26\" y=\"137\" width=\"61\" height=\"13\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"height\" constant=\"13\" id=\"5wZ-x4-EKn\"/>\n                                    <constraint firstAttribute=\"width\" constant=\"116\" id=\"TdO-UU-WIl\"/>\n                                </constraints>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"path:\" id=\"Gqr-cR-TAF\">\n                                    <font key=\"font\" size=\"10\" name=\"Menlo-Regular\"/>\n                                    <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                            <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"499\" fixedFrame=\"YES\" allowsCharacterPickerTouchBarItem=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Nf4-ZN-jcK\" userLabel=\"processID\">\n                                <rect key=\"frame\" x=\"95\" y=\"172\" width=\"228\" height=\"13\"/>\n                                <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                                <textFieldCell key=\"cell\" lineBreakMode=\"truncatingMiddle\" truncatesLastVisibleLine=\"YES\" selectable=\"YES\" allowsUndo=\"NO\" sendsActionOnEndEditing=\"YES\" id=\"ezD-RZ-q5S\">\n                                    <font key=\"font\" size=\"11\" name=\"Menlo-Regular\"/>\n                                    <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                            <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" ambiguous=\"YES\" allowsCharacterPickerTouchBarItem=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"CvP-W3-IE1\">\n                                <rect key=\"frame\" x=\"338\" y=\"155\" width=\"120\" height=\"13\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"width\" constant=\"116\" id=\"TkJ-p4-gfN\"/>\n                                    <constraint firstAttribute=\"height\" constant=\"13\" id=\"o6B-Y3-CkO\"/>\n                                </constraints>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"port/protocol:\" id=\"31V-e4-dgv\">\n                                    <font key=\"font\" size=\"10\" name=\"Menlo-Regular\"/>\n                                    <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                            <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" ambiguous=\"YES\" allowsCharacterPickerTouchBarItem=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"sBf-sv-RQG\">\n                                <rect key=\"frame\" x=\"338\" y=\"172\" width=\"101\" height=\"13\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"height\" constant=\"13\" id=\"Dx0-Jz-YrF\"/>\n                                    <constraint firstAttribute=\"width\" constant=\"116\" id=\"jJK-SD-E7E\"/>\n                                </constraints>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"ip address:\" id=\"vmZ-KS-uuK\">\n                                    <font key=\"font\" size=\"10\" name=\"Menlo-Regular\"/>\n                                    <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                            <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" ambiguous=\"YES\" allowsCharacterPickerTouchBarItem=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"3gh-BJ-48m\">\n                                <rect key=\"frame\" x=\"338\" y=\"191\" width=\"237\" height=\"15\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"height\" constant=\"15\" id=\"4j8-6h-7HU\"/>\n                                    <constraint firstAttribute=\"width\" constant=\"340\" id=\"P0z-In-3cz\"/>\n                                </constraints>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Connection:\" id=\"8eV-Ag-i7n\">\n                                    <font key=\"font\" size=\"13\" name=\"Menlo-Bold\"/>\n                                    <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                            <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" ambiguous=\"YES\" allowsCharacterPickerTouchBarItem=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"KcR-uG-3PA\">\n                                <rect key=\"frame\" x=\"338\" y=\"137\" width=\"120\" height=\"13\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"width\" constant=\"116\" id=\"7UE-Lp-fEN\"/>\n                                    <constraint firstAttribute=\"height\" constant=\"13\" id=\"oH2-f4-nmV\"/>\n                                </constraints>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"(reverse) dns:\" id=\"Fxr-aW-bT2\">\n                                    <font key=\"font\" size=\"10\" name=\"Menlo-Regular\"/>\n                                    <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                            <popUpButton springLoaded=\"YES\" verticalHuggingPriority=\"750\" ambiguous=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"TSg-6a-DVi\">\n                                <rect key=\"frame\" x=\"24\" y=\"55\" width=\"168\" height=\"25\"/>\n                                <popUpButtonCell key=\"cell\" type=\"push\" title=\"Process\" bezelStyle=\"rounded\" alignment=\"left\" lineBreakMode=\"truncatingTail\" state=\"on\" borderStyle=\"borderAndBezel\" imageScaling=\"proportionallyDown\" inset=\"2\" selectedItem=\"Iys-aY-OZ4\" id=\"L5E-Sx-brM\">\n                                    <behavior key=\"behavior\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                    <font key=\"font\" metaFont=\"message\"/>\n                                    <menu key=\"menu\" id=\"6j9-v7-G9I\">\n                                        <items>\n                                            <menuItem title=\"Process\" state=\"on\" id=\"Iys-aY-OZ4\"/>\n                                            <menuItem title=\"Remote Endpoint\" id=\"N6E-eT-Q39\"/>\n                                        </items>\n                                    </menu>\n                                </popUpButtonCell>\n                                <constraints>\n                                    <constraint firstAttribute=\"width\" constant=\"161\" id=\"wyb-In-iCd\"/>\n                                </constraints>\n                            </popUpButton>\n                            <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" ambiguous=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"aSA-bY-aUV\">\n                                <rect key=\"frame\" x=\"25\" y=\"86\" width=\"164\" height=\"14\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"width\" constant=\"160\" id=\"Xxu-Od-Fzt\"/>\n                                </constraints>\n                                <textFieldCell key=\"cell\" lineBreakMode=\"clipping\" title=\"Rule Scope:\" id=\"G2Q-QQ-EX7\">\n                                    <font key=\"font\" size=\"12\" name=\"Menlo-Regular\"/>\n                                    <color key=\"textColor\" name=\"tertiaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                            <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" ambiguous=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"giZ-wY-Jcm\">\n                                <rect key=\"frame\" x=\"230\" y=\"86\" width=\"163\" height=\"14\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"width\" constant=\"159\" id=\"scm-yX-y4j\"/>\n                                </constraints>\n                                <textFieldCell key=\"cell\" lineBreakMode=\"clipping\" title=\"Rule Duration:\" id=\"9OD-rL-0J2\">\n                                    <font key=\"font\" size=\"12\" name=\"Menlo-Regular\"/>\n                                    <color key=\"textColor\" name=\"tertiaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                            <button tag=\"100\" verticalHuggingPriority=\"750\" ambiguous=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"n0b-XP-ZUr\">\n                                <rect key=\"frame\" x=\"232\" y=\"62\" width=\"212\" height=\"18\"/>\n                                <buttonCell key=\"cell\" type=\"radio\" title=\"Always\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"Ubf-5c-Fd2\">\n                                    <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                    <font key=\"font\" size=\"12\" name=\"Menlo-Regular\"/>\n                                </buttonCell>\n                                <constraints>\n                                    <constraint firstAttribute=\"width\" constant=\"212\" id=\"L6T-hh-ftl\"/>\n                                </constraints>\n                                <connections>\n                                    <action selector=\"ruleDurationHandler:\" target=\"-2\" id=\"qTH-Se-UF7\"/>\n                                </connections>\n                            </button>\n                            <button tag=\"101\" verticalHuggingPriority=\"750\" ambiguous=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"FV9-wU-TBa\">\n                                <rect key=\"frame\" x=\"232\" y=\"39\" width=\"212\" height=\"18\"/>\n                                <buttonCell key=\"cell\" type=\"radio\" title=\"Process lifetime\" bezelStyle=\"regularSquare\" imagePosition=\"left\" inset=\"2\" id=\"80z-6q-eWC\">\n                                    <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                    <font key=\"font\" size=\"12\" name=\"Menlo-Regular\"/>\n                                </buttonCell>\n                                <constraints>\n                                    <constraint firstAttribute=\"width\" constant=\"212\" id=\"cvJ-Vb-eLf\"/>\n                                </constraints>\n                                <connections>\n                                    <action selector=\"ruleDurationHandler:\" target=\"-2\" id=\"Ymv-C7-U6Z\"/>\n                                </connections>\n                            </button>\n                            <button tag=\"102\" verticalHuggingPriority=\"750\" ambiguous=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Xf4-RL-C1a\">\n                                <rect key=\"frame\" x=\"232\" y=\"17\" width=\"102\" height=\"18\"/>\n                                <buttonCell key=\"cell\" type=\"radio\" title=\"Expires in:\" bezelStyle=\"regularSquare\" imagePosition=\"left\" scrollable=\"YES\" lineBreakMode=\"clipping\" inset=\"2\" id=\"Wn5-T5-boq\">\n                                    <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                    <font key=\"font\" size=\"12\" name=\"Menlo-Regular\"/>\n                                </buttonCell>\n                                <constraints>\n                                    <constraint firstAttribute=\"height\" constant=\"14\" id=\"9Aq-fr-2HJ\"/>\n                                </constraints>\n                                <connections>\n                                    <action selector=\"ruleDurationHandler:\" target=\"-2\" id=\"hr2-kr-2BY\"/>\n                                </connections>\n                            </button>\n                            <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" ambiguous=\"YES\" allowsCharacterPickerTouchBarItem=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"hI7-ev-MZU\">\n                                <rect key=\"frame\" x=\"27\" y=\"191\" width=\"167\" height=\"15\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"height\" constant=\"15\" id=\"zi4-Pm-OPu\"/>\n                                </constraints>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Process:\" id=\"Pp2-2W-YkT\">\n                                    <font key=\"font\" size=\"13\" name=\"Menlo-Bold\"/>\n                                    <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                            <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"499\" fixedFrame=\"YES\" allowsCharacterPickerTouchBarItem=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ndx-hj-9e4\" userLabel=\"processArgs\">\n                                <rect key=\"frame\" x=\"95\" y=\"155\" width=\"228\" height=\"13\"/>\n                                <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" truncatesLastVisibleLine=\"YES\" selectable=\"YES\" allowsUndo=\"NO\" sendsActionOnEndEditing=\"YES\" id=\"HEl-Es-GF3\">\n                                    <font key=\"font\" size=\"11\" name=\"Menlo-Regular\"/>\n                                    <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                            <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" ambiguous=\"YES\" allowsCharacterPickerTouchBarItem=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"0yy-0X-fb5\" userLabel=\"ipAddr\">\n                                <rect key=\"frame\" x=\"440\" y=\"172\" width=\"166\" height=\"13\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"height\" constant=\"13\" id=\"I86-1o-p4T\"/>\n                                </constraints>\n                                <textFieldCell key=\"cell\" lineBreakMode=\"truncatingMiddle\" truncatesLastVisibleLine=\"YES\" selectable=\"YES\" allowsUndo=\"NO\" sendsActionOnEndEditing=\"YES\" id=\"zYo-Ag-S29\">\n                                    <font key=\"font\" size=\"11\" name=\"Menlo-Regular\"/>\n                                    <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                            <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" ambiguous=\"YES\" allowsCharacterPickerTouchBarItem=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"5Lz-xv-ErN\" userLabel=\"portProto\">\n                                <rect key=\"frame\" x=\"440\" y=\"155\" width=\"166\" height=\"13\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"height\" constant=\"13\" id=\"Xfu-tH-7WY\"/>\n                                </constraints>\n                                <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" truncatesLastVisibleLine=\"YES\" selectable=\"YES\" allowsUndo=\"NO\" id=\"XV5-p0-Rs5\">\n                                    <font key=\"font\" size=\"11\" name=\"Menlo-Regular\"/>\n                                    <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                            <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"hbn-rf-Xhf\">\n                                <rect key=\"frame\" x=\"337\" y=\"12\" width=\"33\" height=\"24\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"width\" constant=\"33\" id=\"h1i-xh-JbU\"/>\n                                    <constraint firstAttribute=\"height\" constant=\"24\" id=\"xep-xu-zRP\"/>\n                                </constraints>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" placeholderString=\"HH\" drawsBackground=\"YES\" id=\"abH-g6-95w\">\n                                    <numberFormatter key=\"formatter\" formatterBehavior=\"default10_4\" numberStyle=\"decimal\" formatWidth=\"-1\" minimumIntegerDigits=\"1\" maximumIntegerDigits=\"2000000000\" maximumFractionDigits=\"3\" id=\"ZA0-wJ-nxG\"/>\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                            <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" ambiguous=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"qWw-SE-uh0\">\n                                <rect key=\"frame\" x=\"26\" y=\"19\" width=\"166\" height=\"14\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"width\" constant=\"163\" id=\"hG3-8J-VRs\"/>\n                                </constraints>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"left\" title=\"Time stamp: \" id=\"ybM-PR-IbA\">\n                                    <font key=\"font\" size=\"11\" name=\"Menlo-Regular\"/>\n                                    <color key=\"textColor\" name=\"tertiaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                            <scrollView fixedFrame=\"YES\" borderType=\"none\" horizontalLineScroll=\"10\" horizontalPageScroll=\"10\" verticalLineScroll=\"10\" verticalPageScroll=\"10\" hasHorizontalScroller=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"j55-Oy-dpj\" userLabel=\"Scroll View - Path\">\n                                <rect key=\"frame\" x=\"93\" y=\"110\" width=\"237\" height=\"40\"/>\n                                <autoresizingMask key=\"autoresizingMask\"/>\n                                <clipView key=\"contentView\" drawsBackground=\"NO\" id=\"FpV-9i-AxL\">\n                                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"237\" height=\"40\"/>\n                                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                    <subviews>\n                                        <textView wantsLayer=\"YES\" editable=\"NO\" drawsBackground=\"NO\" importsGraphics=\"NO\" richText=\"NO\" verticallyResizable=\"YES\" id=\"Jci-ZZ-1Ro\">\n                                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"237\" height=\"40\"/>\n                                            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <size key=\"minSize\" width=\"237\" height=\"40\"/>\n                                            <size key=\"maxSize\" width=\"250\" height=\"10000000\"/>\n                                            <attributedString key=\"textStorage\">\n                                                <fragment content=\"process path\">\n                                                    <attributes>\n                                                        <color key=\"NSColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                        <font key=\"NSFont\" size=\"11\" name=\"Menlo-Regular\"/>\n                                                        <paragraphStyle key=\"NSParagraphStyle\" alignment=\"natural\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\"/>\n                                                    </attributes>\n                                                </fragment>\n                                            </attributedString>\n                                        </textView>\n                                    </subviews>\n                                    <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </clipView>\n                                <scroller key=\"horizontalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"YES\" id=\"TFP-8F-JLn\">\n                                    <rect key=\"frame\" x=\"-100\" y=\"-100\" width=\"240\" height=\"16\"/>\n                                    <autoresizingMask key=\"autoresizingMask\"/>\n                                </scroller>\n                                <scroller key=\"verticalScroller\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"NO\" id=\"QbS-Dj-TFs\">\n                                    <rect key=\"frame\" x=\"220\" y=\"0.0\" width=\"17\" height=\"40\"/>\n                                    <autoresizingMask key=\"autoresizingMask\"/>\n                                </scroller>\n                            </scrollView>\n                            <scrollView fixedFrame=\"YES\" borderType=\"none\" horizontalLineScroll=\"10\" horizontalPageScroll=\"10\" verticalLineScroll=\"10\" verticalPageScroll=\"10\" hasHorizontalScroller=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"GGY-OR-jxb\" userLabel=\"Scroll View - DNS\">\n                                <rect key=\"frame\" x=\"439\" y=\"111\" width=\"208\" height=\"40\"/>\n                                <autoresizingMask key=\"autoresizingMask\"/>\n                                <clipView key=\"contentView\" drawsBackground=\"NO\" id=\"h0J-S8-yD9\">\n                                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"208\" height=\"40\"/>\n                                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                    <subviews>\n                                        <textView wantsLayer=\"YES\" editable=\"NO\" drawsBackground=\"NO\" importsGraphics=\"NO\" richText=\"NO\" verticallyResizable=\"YES\" spellingCorrection=\"YES\" smartInsertDelete=\"YES\" id=\"BQn-nb-yUE\">\n                                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"208\" height=\"40\"/>\n                                            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <size key=\"minSize\" width=\"208\" height=\"40\"/>\n                                            <size key=\"maxSize\" width=\"240\" height=\"10000000\"/>\n                                            <attributedString key=\"textStorage\">\n                                                <fragment content=\"resolving...\">\n                                                    <attributes>\n                                                        <color key=\"NSColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                        <font key=\"NSFont\" size=\"11\" name=\"Menlo-Regular\"/>\n                                                        <font key=\"NSOriginalFont\" size=\"12\" name=\"Helvetica\"/>\n                                                        <paragraphStyle key=\"NSParagraphStyle\" alignment=\"natural\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\"/>\n                                                    </attributes>\n                                                </fragment>\n                                            </attributedString>\n                                        </textView>\n                                    </subviews>\n                                </clipView>\n                                <scroller key=\"horizontalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"YES\" id=\"P6O-sw-Vcf\">\n                                    <rect key=\"frame\" x=\"-100\" y=\"-100\" width=\"240\" height=\"16\"/>\n                                    <autoresizingMask key=\"autoresizingMask\"/>\n                                </scroller>\n                                <scroller key=\"verticalScroller\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"NO\" id=\"v1S-cT-pNh\">\n                                    <rect key=\"frame\" x=\"191\" y=\"0.0\" width=\"17\" height=\"40\"/>\n                                    <autoresizingMask key=\"autoresizingMask\"/>\n                                </scroller>\n                            </scrollView>\n                            <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" ambiguous=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"lal-dX-T3V\">\n                                <rect key=\"frame\" x=\"373\" y=\"17\" width=\"12\" height=\"14\"/>\n                                <textFieldCell key=\"cell\" lineBreakMode=\"clipping\" title=\":\" id=\"cUm-e3-Dh5\">\n                                    <font key=\"font\" size=\"12\" name=\"Menlo-Regular\"/>\n                                    <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                            <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"yCo-33-DDd\">\n                                <rect key=\"frame\" x=\"388\" y=\"12\" width=\"35\" height=\"24\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"width\" constant=\"35\" id=\"NFL-0Y-bXj\"/>\n                                    <constraint firstAttribute=\"height\" constant=\"24\" id=\"OVi-I6-Cdd\"/>\n                                </constraints>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" placeholderString=\"mm\" drawsBackground=\"YES\" id=\"AuV-oM-p6G\">\n                                    <numberFormatter key=\"formatter\" formatterBehavior=\"default10_4\" numberStyle=\"decimal\" formatWidth=\"-1\" minimumIntegerDigits=\"1\" maximumIntegerDigits=\"2000000000\" maximumFractionDigits=\"3\" id=\"69C-0x-5ed\"/>\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                        </subviews>\n                        <constraints>\n                            <constraint firstItem=\"FV9-wU-TBa\" firstAttribute=\"leading\" secondItem=\"xge-2z-T9l\" secondAttribute=\"leading\" constant=\"232\" id=\"5Wi-47-a3c\"/>\n                            <constraint firstItem=\"Xf4-RL-C1a\" firstAttribute=\"leading\" secondItem=\"xge-2z-T9l\" secondAttribute=\"leading\" constant=\"232\" id=\"UE6-1O-GTy\"/>\n                            <constraint firstAttribute=\"bottom\" secondItem=\"yCo-33-DDd\" secondAttribute=\"bottom\" constant=\"12\" id=\"ZRP-du-rEk\"/>\n                            <constraint firstItem=\"yCo-33-DDd\" firstAttribute=\"leading\" secondItem=\"lal-dX-T3V\" secondAttribute=\"trailing\" constant=\"5\" id=\"h63-kL-sLq\"/>\n                            <constraint firstItem=\"hbn-rf-Xhf\" firstAttribute=\"leading\" secondItem=\"Xf4-RL-C1a\" secondAttribute=\"trailing\" constant=\"3\" id=\"iMg-X4-vst\"/>\n                            <constraint firstAttribute=\"bottom\" secondItem=\"hbn-rf-Xhf\" secondAttribute=\"bottom\" constant=\"12\" id=\"n1L-4g-LBv\"/>\n                            <constraint firstItem=\"n0b-XP-ZUr\" firstAttribute=\"leading\" secondItem=\"xge-2z-T9l\" secondAttribute=\"leading\" constant=\"232\" id=\"qby-li-t9f\"/>\n                            <constraint firstItem=\"giZ-wY-Jcm\" firstAttribute=\"leading\" secondItem=\"xge-2z-T9l\" secondAttribute=\"leading\" constant=\"232\" id=\"uga-fg-Obv\"/>\n                            <constraint firstItem=\"lal-dX-T3V\" firstAttribute=\"leading\" secondItem=\"hbn-rf-Xhf\" secondAttribute=\"trailing\" constant=\"5\" id=\"zeH-jZ-fIo\"/>\n                        </constraints>\n                    </customView>\n                    <imageView horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"fJv-Iu-3gy\">\n                        <rect key=\"frame\" x=\"29\" y=\"316\" width=\"136\" height=\"116\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"width\" constant=\"136\" id=\"tbx-Yu-Qks\"/>\n                            <constraint firstAttribute=\"height\" constant=\"116\" id=\"uE7-zm-rBz\"/>\n                        </constraints>\n                        <imageCell key=\"cell\" refusesFirstResponder=\"YES\" alignment=\"left\" imageScaling=\"proportionallyUpOrDown\" image=\"Icon\" id=\"Upz-Sh-hHf\"/>\n                    </imageView>\n                    <scrollView borderType=\"none\" horizontalLineScroll=\"10\" horizontalPageScroll=\"10\" verticalLineScroll=\"10\" verticalPageScroll=\"10\" hasHorizontalScroller=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"aVD-pe-6gz\">\n                        <rect key=\"frame\" x=\"173\" y=\"316\" width=\"474\" height=\"67\"/>\n                        <clipView key=\"contentView\" drawsBackground=\"NO\" id=\"7RC-65-dBA\">\n                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"474\" height=\"67\"/>\n                            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                            <subviews>\n                                <textView wantsLayer=\"YES\" editable=\"NO\" drawsBackground=\"NO\" importsGraphics=\"NO\" richText=\"NO\" verticallyResizable=\"YES\" spellingCorrection=\"YES\" smartInsertDelete=\"YES\" id=\"HWR-Ex-H2f\">\n                                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"474\" height=\"67\"/>\n                                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                    <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <size key=\"minSize\" width=\"474\" height=\"67\"/>\n                                    <size key=\"maxSize\" width=\"474\" height=\"10000000\"/>\n                                    <attributedString key=\"textStorage\">\n                                        <fragment content=\"is connecting to...\">\n                                            <attributes>\n                                                <color key=\"NSColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <font key=\"NSFont\" size=\"14\" name=\"Menlo-Bold\"/>\n                                                <font key=\"NSOriginalFont\" size=\"12\" name=\"Helvetica\"/>\n                                                <paragraphStyle key=\"NSParagraphStyle\" alignment=\"natural\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\"/>\n                                            </attributes>\n                                        </fragment>\n                                    </attributedString>\n                                </textView>\n                            </subviews>\n                        </clipView>\n                        <scroller key=\"horizontalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"YES\" id=\"f2y-zH-93m\">\n                            <rect key=\"frame\" x=\"-100\" y=\"-100\" width=\"240\" height=\"16\"/>\n                            <autoresizingMask key=\"autoresizingMask\"/>\n                        </scroller>\n                        <scroller key=\"verticalScroller\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"NO\" id=\"DB5-qg-AiF\">\n                            <rect key=\"frame\" x=\"457\" y=\"0.0\" width=\"17\" height=\"67\"/>\n                            <autoresizingMask key=\"autoresizingMask\"/>\n                        </scroller>\n                    </scrollView>\n                    <button tag=\"1\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"yg5-Dg-d1n\">\n                        <rect key=\"frame\" x=\"510\" y=\"253\" width=\"137\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Allow\" bezelStyle=\"rounded\" alignment=\"center\" controlSize=\"large\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"Zk5-p6-VV3\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" size=\"15\" name=\"Menlo-Bold\"/>\n                        </buttonCell>\n                        <constraints>\n                            <constraint firstAttribute=\"width\" constant=\"137\" id=\"hEJ-it-TPc\"/>\n                            <constraint firstAttribute=\"height\" constant=\"32\" id=\"pLT-UN-ptY\"/>\n                        </constraints>\n                        <connections>\n                            <action selector=\"handleUserResponse:\" target=\"-2\" id=\"gbD-4o-vfb\"/>\n                        </connections>\n                    </button>\n                </subviews>\n                <constraints>\n                    <constraint firstItem=\"aVD-pe-6gz\" firstAttribute=\"bottom\" secondItem=\"fJv-Iu-3gy\" secondAttribute=\"bottom\" id=\"4BY-1I-w7e\"/>\n                    <constraint firstItem=\"i1i-s4-Q02\" firstAttribute=\"top\" secondItem=\"se5-gp-TjO\" secondAttribute=\"top\" constant=\"39\" id=\"8zf-7S-usv\"/>\n                    <constraint firstItem=\"32G-48-5jq\" firstAttribute=\"leading\" secondItem=\"se5-gp-TjO\" secondAttribute=\"leading\" constant=\"79\" id=\"Ah9-AT-pHO\"/>\n                    <constraint firstItem=\"aVD-pe-6gz\" firstAttribute=\"top\" secondItem=\"i1i-s4-Q02\" secondAttribute=\"bottom\" constant=\"4\" id=\"Co2-n6-eKl\"/>\n                    <constraint firstItem=\"tWx-6z-uXa\" firstAttribute=\"top\" secondItem=\"se5-gp-TjO\" secondAttribute=\"top\" constant=\"216\" id=\"G9m-vM-iqS\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"aVD-pe-6gz\" secondAttribute=\"trailing\" constant=\"20\" symbolic=\"YES\" id=\"ILG-m4-76j\"/>\n                    <constraint firstItem=\"aVD-pe-6gz\" firstAttribute=\"top\" secondItem=\"se5-gp-TjO\" secondAttribute=\"top\" constant=\"69\" id=\"KKE-KM-Slu\"/>\n                    <constraint firstItem=\"QJt-zQ-EMG\" firstAttribute=\"top\" secondItem=\"fJv-Iu-3gy\" secondAttribute=\"bottom\" constant=\"81\" id=\"MKZ-Jb-2Ws\"/>\n                    <constraint firstItem=\"Aix-a5-CPT\" firstAttribute=\"top\" secondItem=\"se5-gp-TjO\" secondAttribute=\"top\" constant=\"167\" id=\"Nka-RK-7Oi\"/>\n                    <constraint firstItem=\"32G-48-5jq\" firstAttribute=\"top\" secondItem=\"se5-gp-TjO\" secondAttribute=\"top\" constant=\"163\" id=\"Rra-RY-2UK\"/>\n                    <constraint firstItem=\"fJv-Iu-3gy\" firstAttribute=\"leading\" secondItem=\"se5-gp-TjO\" secondAttribute=\"leading\" constant=\"29\" id=\"ZOd-Lr-GPA\"/>\n                    <constraint firstItem=\"PJQ-Iq-93l\" firstAttribute=\"leading\" secondItem=\"se5-gp-TjO\" secondAttribute=\"leading\" constant=\"134\" id=\"btD-IL-RH2\"/>\n                    <constraint firstItem=\"i1i-s4-Q02\" firstAttribute=\"leading\" secondItem=\"se5-gp-TjO\" secondAttribute=\"leading\" constant=\"176\" id=\"d6R-YA-gQl\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"i1i-s4-Q02\" secondAttribute=\"trailing\" constant=\"20\" symbolic=\"YES\" id=\"dfc-jT-99A\"/>\n                    <constraint firstItem=\"QJt-zQ-EMG\" firstAttribute=\"leading\" secondItem=\"fJv-Iu-3gy\" secondAttribute=\"leading\" id=\"eXm-Pc-sEE\"/>\n                    <constraint firstItem=\"FqM-TW-r0o\" firstAttribute=\"top\" secondItem=\"se5-gp-TjO\" secondAttribute=\"top\" constant=\"157\" id=\"env-oq-jyV\"/>\n                    <constraint firstItem=\"yg5-Dg-d1n\" firstAttribute=\"top\" secondItem=\"se5-gp-TjO\" secondAttribute=\"top\" constant=\"167\" id=\"gKh-GD-cfR\"/>\n                    <constraint firstItem=\"PJQ-Iq-93l\" firstAttribute=\"top\" secondItem=\"se5-gp-TjO\" secondAttribute=\"top\" constant=\"166\" id=\"gL0-hA-FPT\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"yg5-Dg-d1n\" secondAttribute=\"trailing\" constant=\"20\" symbolic=\"YES\" id=\"hW0-Qb-Jw8\"/>\n                    <constraint firstItem=\"aVD-pe-6gz\" firstAttribute=\"leading\" secondItem=\"se5-gp-TjO\" secondAttribute=\"leading\" constant=\"173\" id=\"lH6-ol-jKl\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"Aix-a5-CPT\" secondAttribute=\"trailing\" constant=\"192\" id=\"lkJ-sh-BUN\"/>\n                    <constraint firstItem=\"tWx-6z-uXa\" firstAttribute=\"leading\" secondItem=\"QJt-zQ-EMG\" secondAttribute=\"trailing\" constant=\"3\" id=\"oDW-WI-pwM\"/>\n                    <constraint firstItem=\"FqM-TW-r0o\" firstAttribute=\"leading\" secondItem=\"se5-gp-TjO\" secondAttribute=\"leading\" constant=\"26\" id=\"uQI-s0-RzI\"/>\n                    <constraint firstItem=\"fJv-Iu-3gy\" firstAttribute=\"top\" secondItem=\"se5-gp-TjO\" secondAttribute=\"top\" constant=\"20\" id=\"yoL-Uz-mlH\"/>\n                </constraints>\n            </view>\n            <connections>\n                <outlet property=\"delegate\" destination=\"-2\" id=\"0bl-1N-AYu\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"234.5\" y=\"252\"/>\n        </window>\n        <view id=\"rai-3Q-8AG\" userLabel=\"SigningInfoView\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"547\" height=\"202\"/>\n            <autoresizingMask key=\"autoresizingMask\"/>\n            <subviews>\n                <imageView horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"JFu-zg-Xoc\">\n                    <rect key=\"frame\" x=\"20\" y=\"134\" width=\"48\" height=\"48\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <imageCell key=\"cell\" refusesFirstResponder=\"YES\" alignment=\"left\" imageScaling=\"proportionallyDown\" id=\"q4p-9m-2Jl\"/>\n                </imageView>\n                <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" setsMaxLayoutWidthAtFirstLayout=\"YES\" allowsCharacterPickerTouchBarItem=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"jNc-sZ-Rpj\" userLabel=\"messageLabel\">\n                    <rect key=\"frame\" x=\"74\" y=\"146\" width=\"393\" height=\"25\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" alignment=\"left\" title=\"message\" id=\"Ssw-3u-wEC\">\n                        <font key=\"font\" size=\"15\" name=\"Menlo-Bold\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" allowsCharacterPickerTouchBarItem=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"xft-9d-bha\">\n                    <rect key=\"frame\" x=\"18\" y=\"72\" width=\"511\" height=\"18\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Signing Authorities:\" id=\"D1C-aK-AFU\">\n                        <font key=\"font\" size=\"12\" name=\"Menlo-Bold\"/>\n                        <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" allowsCharacterPickerTouchBarItem=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"bdt-6r-ZQN\">\n                    <rect key=\"frame\" x=\"18\" y=\"107\" width=\"81\" height=\"18\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Details:\" id=\"b63-At-csb\">\n                        <font key=\"font\" size=\"12\" name=\"Menlo-Bold\"/>\n                        <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" setsMaxLayoutWidthAtFirstLayout=\"YES\" allowsCharacterPickerTouchBarItem=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"md4-Vv-ZQL\" userLabel=\"messageLabel\">\n                    <rect key=\"frame\" x=\"103\" y=\"93\" width=\"426\" height=\"32\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" alignment=\"left\" id=\"m7h-3S-cCv\">\n                        <font key=\"font\" size=\"12\" name=\"Menlo-Regular\"/>\n                        <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" tag=\"1\" setsMaxLayoutWidthAtFirstLayout=\"YES\" allowsCharacterPickerTouchBarItem=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Dkp-Qw-TZb\" userLabel=\"messageLabel\">\n                    <rect key=\"frame\" x=\"18\" y=\"53\" width=\"511\" height=\"18\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" sendsActionOnEndEditing=\"YES\" alignment=\"left\" title=\" -\" id=\"Ki9-ld-5Xu\">\n                        <font key=\"font\" size=\"12\" name=\"Menlo-Regular\"/>\n                        <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" tag=\"2\" setsMaxLayoutWidthAtFirstLayout=\"YES\" allowsCharacterPickerTouchBarItem=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"hWl-Gd-eYT\" userLabel=\"messageLabel\">\n                    <rect key=\"frame\" x=\"18\" y=\"35\" width=\"511\" height=\"18\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" sendsActionOnEndEditing=\"YES\" alignment=\"left\" title=\" -\" id=\"1zg-95-QM7\">\n                        <font key=\"font\" size=\"12\" name=\"Menlo-Regular\"/>\n                        <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" tag=\"3\" setsMaxLayoutWidthAtFirstLayout=\"YES\" allowsCharacterPickerTouchBarItem=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"jpF-Wn-qHJ\" userLabel=\"messageLabel\">\n                    <rect key=\"frame\" x=\"18\" y=\"17\" width=\"511\" height=\"18\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" sendsActionOnEndEditing=\"YES\" alignment=\"left\" title=\" -\" id=\"FLb-1c-otA\">\n                        <font key=\"font\" size=\"12\" name=\"Menlo-Regular\"/>\n                        <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n            </subviews>\n            <point key=\"canvasLocation\" x=\"448.5\" y=\"737\"/>\n        </view>\n        <view id=\"ZMg-yW-Bgc\" userLabel=\"VirusTotalView\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"345\" height=\"102\"/>\n            <autoresizingMask key=\"autoresizingMask\"/>\n            <subviews>\n                <imageView horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Ihw-rO-Pvt\">\n                    <rect key=\"frame\" x=\"20\" y=\"27\" width=\"48\" height=\"48\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <imageCell key=\"cell\" refusesFirstResponder=\"YES\" alignment=\"left\" imageScaling=\"proportionallyDown\" image=\"VTIcon\" id=\"BTM-RA-73B\"/>\n                </imageView>\n                <scrollView fixedFrame=\"YES\" borderType=\"none\" horizontalLineScroll=\"10\" horizontalPageScroll=\"10\" verticalLineScroll=\"10\" verticalPageScroll=\"10\" hasHorizontalScroller=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Unp-vM-tdL\">\n                    <rect key=\"frame\" x=\"76\" y=\"20\" width=\"249\" height=\"52\"/>\n                    <autoresizingMask key=\"autoresizingMask\"/>\n                    <clipView key=\"contentView\" drawsBackground=\"NO\" id=\"gk8-xs-iU6\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"249\" height=\"52\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                        <subviews>\n                            <textView wantsLayer=\"YES\" editable=\"NO\" drawsBackground=\"NO\" importsGraphics=\"NO\" richText=\"NO\" verticallyResizable=\"YES\" spellingCorrection=\"YES\" smartInsertDelete=\"YES\" id=\"GrM-w9-LdZ\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"249\" height=\"52\"/>\n                                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <size key=\"minSize\" width=\"249\" height=\"52\"/>\n                                <size key=\"maxSize\" width=\"263\" height=\"10000000\"/>\n                                <attributedString key=\"textStorage\">\n                                    <fragment content=\"Querying VirusTotal...\">\n                                        <attributes>\n                                            <color key=\"NSColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <font key=\"NSFont\" size=\"12\" name=\"Menlo-Regular\"/>\n                                            <paragraphStyle key=\"NSParagraphStyle\" alignment=\"natural\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\"/>\n                                        </attributes>\n                                    </fragment>\n                                </attributedString>\n                            </textView>\n                        </subviews>\n                    </clipView>\n                    <scroller key=\"horizontalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"YES\" id=\"m2Y-zn-7kG\">\n                        <rect key=\"frame\" x=\"-100\" y=\"-100\" width=\"240\" height=\"16\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </scroller>\n                    <scroller key=\"verticalScroller\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"NO\" id=\"HUx-X1-wrH\">\n                        <rect key=\"frame\" x=\"233\" y=\"0.0\" width=\"16\" height=\"52\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </scroller>\n                </scrollView>\n                <progressIndicator wantsLayer=\"YES\" horizontalHuggingPriority=\"750\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" maxValue=\"100\" bezeled=\"NO\" indeterminate=\"YES\" style=\"spinning\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"XED-S3-tcb\" userLabel=\"VT Spinner\">\n                    <rect key=\"frame\" x=\"293\" y=\"35\" width=\"32\" height=\"32\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                </progressIndicator>\n            </subviews>\n            <point key=\"canvasLocation\" x=\"-105.5\" y=\"923\"/>\n        </view>\n        <popover id=\"Vmt-MD-3aB\" userLabel=\"Signing Info Popover\">\n            <connections>\n                <outlet property=\"contentViewController\" destination=\"Hya-Lk-Wpj\" id=\"TaC-Pr-azl\"/>\n                <outlet property=\"delegate\" destination=\"Hya-Lk-Wpj\" id=\"E2G-8y-Sfh\"/>\n            </connections>\n        </popover>\n        <viewController id=\"Hya-Lk-Wpj\" userLabel=\"Signing Info Popover View Controller\" customClass=\"SigningInfoViewController\">\n            <connections>\n                <outlet property=\"details\" destination=\"md4-Vv-ZQL\" id=\"kwn-lQ-6O2\"/>\n                <outlet property=\"icon\" destination=\"JFu-zg-Xoc\" id=\"eVd-8Z-dDB\"/>\n                <outlet property=\"message\" destination=\"jNc-sZ-Rpj\" id=\"oJk-zm-87b\"/>\n                <outlet property=\"view\" destination=\"rai-3Q-8AG\" id=\"amJ-ge-paR\"/>\n            </connections>\n        </viewController>\n        <popover id=\"jsE-Vn-PhK\" userLabel=\"VirusTotal Popover\">\n            <connections>\n                <outlet property=\"contentViewController\" destination=\"NMk-MM-wcm\" id=\"ohc-Yo-a3v\"/>\n                <outlet property=\"delegate\" destination=\"NMk-MM-wcm\" id=\"Gho-Fo-wk6\"/>\n            </connections>\n        </popover>\n        <viewController id=\"NMk-MM-wcm\" userLabel=\"VirusTotal Popover View Controller\" customClass=\"VirusTotalViewController\">\n            <connections>\n                <outlet property=\"message\" destination=\"GrM-w9-LdZ\" id=\"tEk-Ke-UZO\"/>\n                <outlet property=\"view\" destination=\"ZMg-yW-Bgc\" id=\"JAN-4T-SK2\"/>\n                <outlet property=\"vtSpinner\" destination=\"XED-S3-tcb\" id=\"MUq-0B-eOH\"/>\n            </connections>\n        </viewController>\n        <popover id=\"25r-fL-QMB\" userLabel=\"Ancestry Popover\">\n            <connections>\n                <outlet property=\"contentViewController\" destination=\"7sP-aX-0Jo\" id=\"LEj-SX-lco\"/>\n                <outlet property=\"delegate\" destination=\"7sP-aX-0Jo\" id=\"dz9-KQ-awh\"/>\n            </connections>\n        </popover>\n        <customObject id=\"7sP-aX-0Jo\" userLabel=\"Ancestry View Controller\" customClass=\"ParentsWindowController\">\n            <connections>\n                <outlet property=\"view\" destination=\"Kwa-G9-AmS\" id=\"5GZ-Ns-Ht1\"/>\n            </connections>\n        </customObject>\n        <view id=\"Kwa-G9-AmS\" userLabel=\"AncestryView\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"307\" height=\"83\"/>\n            <autoresizingMask key=\"autoresizingMask\"/>\n            <subviews>\n                <scrollView focusRingType=\"none\" fixedFrame=\"YES\" borderType=\"none\" autohidesScrollers=\"YES\" horizontalLineScroll=\"20\" horizontalPageScroll=\"10\" verticalLineScroll=\"20\" verticalPageScroll=\"10\" usesPredominantAxisScrolling=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"zLY-OJ-tDG\">\n                    <rect key=\"frame\" x=\"2\" y=\"2\" width=\"303\" height=\"79\"/>\n                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                    <clipView key=\"contentView\" focusRingType=\"none\" id=\"1H0-av-51U\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"303\" height=\"79\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                        <subviews>\n                            <outlineView focusRingType=\"none\" verticalHuggingPriority=\"750\" allowsExpansionToolTips=\"YES\" columnAutoresizingStyle=\"lastColumnOnly\" alternatingRowBackgroundColors=\"YES\" columnReordering=\"NO\" multipleSelection=\"NO\" autosaveColumns=\"NO\" rowHeight=\"18\" indentationPerLevel=\"16\" outlineTableColumn=\"JFW-5C-nvy\" id=\"1Kj-Rh-cPo\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"303\" height=\"79\"/>\n                                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                <size key=\"intercellSpacing\" width=\"3\" height=\"2\"/>\n                                <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <color key=\"gridColor\" name=\"gridColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <tableColumns>\n                                    <tableColumn identifier=\"name\" editable=\"NO\" width=\"271\" minWidth=\"16\" maxWidth=\"1000\" id=\"JFW-5C-nvy\">\n                                        <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"left\" title=\"Name\">\n                                            <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" white=\"0.33333298560000002\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                                        </tableHeaderCell>\n                                        <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" allowsUndo=\"NO\" alignment=\"left\" title=\"Text Cell\" id=\"9sX-aC-eeQ\">\n                                            <font key=\"font\" size=\"13\" name=\"Menlo-Regular\"/>\n                                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                        <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                    </tableColumn>\n                                </tableColumns>\n                                <connections>\n                                    <outlet property=\"dataSource\" destination=\"7sP-aX-0Jo\" id=\"zrE-oY-1Ha\"/>\n                                    <outlet property=\"delegate\" destination=\"7sP-aX-0Jo\" id=\"IDH-ac-lbZ\"/>\n                                </connections>\n                            </outlineView>\n                        </subviews>\n                    </clipView>\n                    <scroller key=\"horizontalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" controlSize=\"mini\" horizontal=\"YES\" id=\"6SM-3p-zO7\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"-14\" width=\"0.0\" height=\"14\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </scroller>\n                    <scroller key=\"verticalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" controlSize=\"mini\" horizontal=\"NO\" id=\"P6o-Sa-Lzv\">\n                        <rect key=\"frame\" x=\"-14\" y=\"0.0\" width=\"14\" height=\"0.0\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </scroller>\n                </scrollView>\n            </subviews>\n            <point key=\"canvasLocation\" x=\"-123\" y=\"765\"/>\n        </view>\n    </objects>\n    <resources>\n        <image name=\"Ancestry\" width=\"50\" height=\"50\"/>\n        <image name=\"Icon\" width=\"144\" height=\"144\"/>\n        <image name=\"Signed\" width=\"512\" height=\"512\"/>\n        <image name=\"VTIcon\" width=\"88\" height=\"80\"/>\n    </resources>\n</document>\n"
  },
  {
    "path": "LuLu/App/Base.lproj/ItemPaths.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"24127\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"24127\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"ItemPathsWindowController\">\n            <connections>\n                <outlet property=\"closeButton\" destination=\"Zmw-oO-5hi\" id=\"DI7-8s-nIy\"/>\n                <outlet property=\"heading\" destination=\"18Q-9B-4bK\" id=\"af8-cU-rNS\"/>\n                <outlet property=\"itemPaths\" destination=\"1wZ-zd-2f4\" id=\"ffE-Jb-I5r\"/>\n                <outlet property=\"window\" destination=\"F0z-JX-Cv5\" id=\"gIp-Ho-8D9\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <window title=\"Window\" allowsToolTipsWhenApplicationIsInactive=\"NO\" autorecalculatesKeyViewLoop=\"NO\" releasedWhenClosed=\"NO\" visibleAtLaunch=\"NO\" animationBehavior=\"default\" id=\"F0z-JX-Cv5\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\" closable=\"YES\" miniaturizable=\"YES\" resizable=\"YES\"/>\n            <windowPositionMask key=\"initialPositionMask\" leftStrut=\"YES\" rightStrut=\"YES\" topStrut=\"YES\" bottomStrut=\"YES\"/>\n            <rect key=\"contentRect\" x=\"196\" y=\"240\" width=\"664\" height=\"270\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"1680\" height=\"1025\"/>\n            <view key=\"contentView\" id=\"se5-gp-TjO\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"664\" height=\"270\"/>\n                <autoresizingMask key=\"autoresizingMask\"/>\n                <subviews>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Zmw-oO-5hi\">\n                        <rect key=\"frame\" x=\"559\" y=\"13\" width=\"92\" height=\"33\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Close\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"ox8-oX-X3s\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" size=\"13\" name=\"Menlo-Bold\"/>\n                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nGw\n</string>\n                        </buttonCell>\n                        <constraints>\n                            <constraint firstAttribute=\"width\" constant=\"78\" id=\"CiC-Cn-UmO\"/>\n                            <constraint firstAttribute=\"height\" constant=\"21\" id=\"YIm-jj-qB9\"/>\n                        </constraints>\n                        <connections>\n                            <action selector=\"closeButtonHandler:\" target=\"-2\" id=\"LwB-dR-X1U\"/>\n                        </connections>\n                    </button>\n                    <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1wZ-zd-2f4\">\n                        <rect key=\"frame\" x=\"18\" y=\"49\" width=\"628\" height=\"177\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"height\" constant=\"177\" id=\"wd9-5r-pJS\"/>\n                        </constraints>\n                        <textFieldCell key=\"cell\" selectable=\"YES\" id=\"NUn-aT-zDv\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"18Q-9B-4bK\">\n                        <rect key=\"frame\" x=\"18\" y=\"234\" width=\"628\" height=\"16\"/>\n                        <textFieldCell key=\"cell\" lineBreakMode=\"clipping\" title=\"Path(s):\" id=\"NhE-Zh-Scd\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                </subviews>\n                <constraints>\n                    <constraint firstItem=\"18Q-9B-4bK\" firstAttribute=\"leading\" secondItem=\"se5-gp-TjO\" secondAttribute=\"leading\" constant=\"20\" id=\"7no-4b-m4X\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"Zmw-oO-5hi\" secondAttribute=\"trailing\" constant=\"20\" id=\"BvZ-tu-N8X\"/>\n                    <constraint firstItem=\"18Q-9B-4bK\" firstAttribute=\"top\" secondItem=\"se5-gp-TjO\" secondAttribute=\"top\" constant=\"20\" id=\"Fo2-Si-Qrb\"/>\n                    <constraint firstItem=\"1wZ-zd-2f4\" firstAttribute=\"leading\" secondItem=\"se5-gp-TjO\" secondAttribute=\"leading\" constant=\"20\" symbolic=\"YES\" id=\"P2h-Oh-9gA\"/>\n                    <constraint firstItem=\"1wZ-zd-2f4\" firstAttribute=\"top\" secondItem=\"se5-gp-TjO\" secondAttribute=\"top\" constant=\"44\" id=\"QbU-ew-3M9\"/>\n                    <constraint firstItem=\"Zmw-oO-5hi\" firstAttribute=\"top\" secondItem=\"1wZ-zd-2f4\" secondAttribute=\"bottom\" constant=\"8\" symbolic=\"YES\" id=\"SVw-qs-RJ8\"/>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"Zmw-oO-5hi\" secondAttribute=\"bottom\" constant=\"20\" id=\"SuO-oe-wQd\"/>\n                    <constraint firstItem=\"1wZ-zd-2f4\" firstAttribute=\"trailing\" secondItem=\"Zmw-oO-5hi\" secondAttribute=\"trailing\" id=\"eHZ-wb-xW5\"/>\n                    <constraint firstItem=\"1wZ-zd-2f4\" firstAttribute=\"top\" secondItem=\"18Q-9B-4bK\" secondAttribute=\"bottom\" constant=\"8\" id=\"fTw-Dt-EKX\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"18Q-9B-4bK\" secondAttribute=\"trailing\" constant=\"20\" symbolic=\"YES\" id=\"lES-hi-riQ\"/>\n                </constraints>\n            </view>\n            <connections>\n                <outlet property=\"delegate\" destination=\"-2\" id=\"0bl-1N-AYu\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"233\" y=\"147\"/>\n        </window>\n    </objects>\n</document>\n"
  },
  {
    "path": "LuLu/App/Base.lproj/MainMenu.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"24128\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"24128\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"NSApplication\">\n            <connections>\n                <outlet property=\"delegate\" destination=\"Voe-Tx-rLC\" id=\"GzC-gU-4Uq\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <customObject id=\"Voe-Tx-rLC\" customClass=\"AppDelegate\">\n            <connections>\n                <outlet property=\"profileSwitchMenuItem\" destination=\"ahR-T8-occ\" id=\"SWm-ux-zVF\"/>\n                <outlet property=\"profilesMenu\" destination=\"1HU-j3-Oa3\" id=\"Mlf-Md-K1Q\"/>\n                <outlet property=\"profilesMenuItem\" destination=\"7kG-TA-f15\" id=\"seZ-kC-yqm\"/>\n                <outlet property=\"statusMenu\" destination=\"bI7-kC-IUx\" id=\"czq-O5-Zp6\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"YLy-65-1bz\" customClass=\"NSFontManager\"/>\n        <menu title=\"Main Menu\" systemMenu=\"main\" autoenablesItems=\"NO\" id=\"uhX-d8-iZM\">\n            <items>\n                <menuItem title=\"LuLu\" id=\"aJV-EX-6bj\" userLabel=\"LuLu\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <menu key=\"submenu\" title=\"LuLu\" systemMenu=\"apple\" id=\"J1I-fS-R65\">\n                        <items>\n                            <menuItem title=\"About LuLu\" id=\"q1D-fP-yr1\" userLabel=\"About LuLu\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"showAbout:\" target=\"Voe-Tx-rLC\" id=\"SNF-kS-dLh\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"AmB-Y6-frK\"/>\n                            <menuItem title=\"Quit LuLu\" keyEquivalent=\"q\" id=\"DEa-wY-se7\">\n                                <connections>\n                                    <action selector=\"quit:\" target=\"Voe-Tx-rLC\" id=\"dd7-Bg-qcz\"/>\n                                </connections>\n                            </menuItem>\n                        </items>\n                    </menu>\n                </menuItem>\n            </items>\n            <point key=\"canvasLocation\" x=\"-59\" y=\"-473\"/>\n        </menu>\n        <menu id=\"bI7-kC-IUx\" userLabel=\"Status Bar Menu\">\n            <items>\n                <menuItem title=\"LULU: enabled\" tag=\"100\" enabled=\"NO\" id=\"w99-Wo-epe\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                </menuItem>\n                <menuItem title=\"Profile: Default\" tag=\"101\" enabled=\"NO\" id=\"mxA-q2-fvN\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                </menuItem>\n                <menuItem isSeparatorItem=\"YES\" id=\"RP3-f7-E06\"/>\n                <menuItem title=\"Disable\" tag=\"102\" id=\"l9M-p8-kao\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                </menuItem>\n                <menuItem isSeparatorItem=\"YES\" id=\"bOQ-2w-DOF\"/>\n                <menuItem title=\"Rules\" id=\"UuL-hi-gEf\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <menu key=\"submenu\" title=\"Rules\" id=\"vb5-99-ejR\">\n                        <items>\n                            <menuItem title=\"Show...\" tag=\"103\" id=\"0Y1-Pq-6Fc\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"MiV-95-jrU\"/>\n                            <menuItem title=\"Add...\" tag=\"104\" id=\"gXq-yc-QnA\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                            </menuItem>\n                            <menuItem title=\"Export...\" tag=\"105\" id=\"aZa-10-Ir1\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                            </menuItem>\n                            <menuItem title=\"Import...\" tag=\"106\" id=\"39l-3u-dUR\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"wFv-yB-0aF\"/>\n                            <menuItem title=\"Cleanup\" tag=\"107\" id=\"Lse-DT-C0z\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                            </menuItem>\n                        </items>\n                    </menu>\n                </menuItem>\n                <menuItem title=\"Profiles\" id=\"7kG-TA-f15\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <menu key=\"submenu\" title=\"Profiles\" id=\"d49-Ze-8oD\">\n                        <items>\n                            <menuItem title=\"Switch\" id=\"ahR-T8-occ\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Switch\" id=\"1HU-j3-Oa3\">\n                                    <items>\n                                        <menuItem id=\"TRi-aL-EeM\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"nxi-S8-RZE\"/>\n                            <menuItem title=\"Manage...\" tag=\"108\" id=\"pF8-Hh-0tW\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                            </menuItem>\n                        </items>\n                    </menu>\n                </menuItem>\n                <menuItem title=\"Settings...\" tag=\"109\" keyEquivalent=\",\" id=\"4Uv-rm-VzQ\"/>\n                <menuItem title=\"Network Monitor...\" tag=\"110\" id=\"VuY-Sy-392\" userLabel=\"Network Monitor...\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                </menuItem>\n                <menuItem isSeparatorItem=\"YES\" id=\"i6W-GD-eRH\"/>\n                <menuItem title=\"Quit LuLu\" tag=\"111\" id=\"QrZ-U2-1Ib\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                </menuItem>\n                <menuItem title=\"Uninstall LuLu\" tag=\"112\" id=\"lns-C6-Aa5\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                </menuItem>\n                <menuItem isSeparatorItem=\"YES\" id=\"4wj-Sr-XSL\"/>\n                <menuItem title=\"Support LuLu 💕\" tag=\"113\" id=\"K0B-xd-gGB\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                </menuItem>\n            </items>\n            <point key=\"canvasLocation\" x=\"55\" y=\"10\"/>\n        </menu>\n    </objects>\n</document>\n"
  },
  {
    "path": "LuLu/App/Base.lproj/Preferences.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"24128\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"24128\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"PrefsWindowController\">\n            <connections>\n                <outlet property=\"addProfileSheet\" destination=\"Zan-q8-ABi\" id=\"OUC-NF-7LI\"/>\n                <outlet property=\"allowList\" destination=\"4CH-OQ-Fxj\" id=\"axT-m4-YDv\"/>\n                <outlet property=\"blockList\" destination=\"n5J-8K-UDy\" id=\"BmA-b5-ppb\"/>\n                <outlet property=\"continueProfileButton\" destination=\"2Fu-cv-a4Y\" id=\"IS9-K8-Lxt\"/>\n                <outlet property=\"listsView\" destination=\"Nkz-5s-cqG\" id=\"Ji5-bu-0Vr\"/>\n                <outlet property=\"modesView\" destination=\"K6i-xr-27e\" id=\"DOb-L3-eeR\"/>\n                <outlet property=\"passiveModeAction\" destination=\"CBy-MH-fsc\" id=\"EwM-q6-3ff\"/>\n                <outlet property=\"passiveModeRules\" destination=\"24D-f1-OZB\" id=\"PdK-Ez-f7h\"/>\n                <outlet property=\"profileNameLabel\" destination=\"ccA-pL-ZcZ\" id=\"gQQ-na-S58\"/>\n                <outlet property=\"profileNameView\" destination=\"6M4-YG-28h\" id=\"oDa-4N-4MI\"/>\n                <outlet property=\"profilesTable\" destination=\"b8D-Cq-rd2\" id=\"TPq-cK-Sv8\"/>\n                <outlet property=\"profilesView\" destination=\"IEt-ZT-jGV\" id=\"GLa-dL-FOW\"/>\n                <outlet property=\"rulesView\" destination=\"378-bj-fYw\" id=\"10Z-g6-I1q\"/>\n                <outlet property=\"selectAllowListButton\" destination=\"S67-V3-uih\" id=\"stx-Rb-hJ5\"/>\n                <outlet property=\"selectBlockListButton\" destination=\"OwS-Bs-2O3\" id=\"Y78-47-q1W\"/>\n                <outlet property=\"showRulesButton\" destination=\"Z2e-jM-Y0P\" id=\"L98-he-Bpb\"/>\n                <outlet property=\"toolbar\" destination=\"V8g-Ya-LK4\" id=\"SH2-6E-QST\"/>\n                <outlet property=\"updateButton\" destination=\"Mtn-pi-zIl\" id=\"Oe1-Jy-nMH\"/>\n                <outlet property=\"updateIndicator\" destination=\"o0T-ra-4H0\" id=\"DwL-OB-WQR\"/>\n                <outlet property=\"updateLabel\" destination=\"Oe2-Ye-1s6\" id=\"1gP-K0-cpP\"/>\n                <outlet property=\"updateView\" destination=\"1OV-sl-cSe\" id=\"Rbj-Y0-Mdg\"/>\n                <outlet property=\"window\" destination=\"F0z-JX-Cv5\" id=\"gIp-Ho-8D9\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <window title=\"Settings\" allowsToolTipsWhenApplicationIsInactive=\"NO\" autorecalculatesKeyViewLoop=\"NO\" releasedWhenClosed=\"NO\" animationBehavior=\"default\" id=\"F0z-JX-Cv5\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\" closable=\"YES\" miniaturizable=\"YES\"/>\n            <rect key=\"contentRect\" x=\"196\" y=\"240\" width=\"650\" height=\"476\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"1280\" height=\"770\"/>\n            <view key=\"contentView\" wantsLayer=\"YES\" id=\"se5-gp-TjO\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"650\" height=\"476\"/>\n                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n            </view>\n            <toolbar key=\"toolbar\" implicitIdentifier=\"C2AC49E3-FD8B-4919-9001-868355500E38\" autosavesConfiguration=\"NO\" showsBaselineSeparator=\"NO\" displayMode=\"iconAndLabel\" sizeMode=\"regular\" id=\"V8g-Ya-LK4\">\n                <allowedToolbarItems>\n                    <toolbarItem implicitItemIdentifier=\"NSToolbarSpaceItem\" id=\"J66-tT-qAf\"/>\n                    <toolbarItem implicitItemIdentifier=\"NSToolbarFlexibleSpaceItem\" id=\"6nW-4K-zf4\"/>\n                    <toolbarItem implicitItemIdentifier=\"99F00439-5E3B-4FBB-BC65-3E1F7EBDDBC6\" explicitItemIdentifier=\"Rules\" label=\"Rules\" paletteLabel=\"Rules\" image=\"PrefsRules\" selectable=\"YES\" id=\"Twx-TJ-y2Q\">\n                        <size key=\"minSize\" width=\"22\" height=\"22\"/>\n                        <size key=\"maxSize\" width=\"22\" height=\"22\"/>\n                        <connections>\n                            <action selector=\"toolbarButtonHandler:\" target=\"-2\" id=\"6sP-cE-opo\"/>\n                        </connections>\n                    </toolbarItem>\n                    <toolbarItem implicitItemIdentifier=\"3F78D487-BA4D-4E1B-8FC6-A844D292C69B\" explicitItemIdentifier=\"Modes\" label=\"Mode\" paletteLabel=\"Mode\" tag=\"1\" image=\"PrefsMode\" selectable=\"YES\" id=\"k0w-Oi-kwd\" userLabel=\"mode\">\n                        <size key=\"minSize\" width=\"22\" height=\"22\"/>\n                        <size key=\"maxSize\" width=\"22\" height=\"22\"/>\n                        <connections>\n                            <action selector=\"toolbarButtonHandler:\" target=\"-2\" id=\"5Bh-RO-nSN\"/>\n                        </connections>\n                    </toolbarItem>\n                    <toolbarItem implicitItemIdentifier=\"384D69C6-2351-417E-9C93-B14039FE440F\" explicitItemIdentifier=\"Lists\" label=\"Lists\" paletteLabel=\"Lists\" tag=\"2\" image=\"PrefsList\" selectable=\"YES\" id=\"rrF-xj-cXp\">\n                        <size key=\"minSize\" width=\"22\" height=\"22\"/>\n                        <size key=\"maxSize\" width=\"22\" height=\"22\"/>\n                        <connections>\n                            <action selector=\"toolbarButtonHandler:\" target=\"-2\" id=\"i0e-Tc-OaX\"/>\n                        </connections>\n                    </toolbarItem>\n                    <toolbarItem implicitItemIdentifier=\"D48AE3A4-6AC7-4E2D-9026-47CD30E3D727\" explicitItemIdentifier=\"Profiles\" label=\"Profiles\" paletteLabel=\"Profiles\" tag=\"3\" image=\"PrefsProfiles\" selectable=\"YES\" id=\"5li-Ut-Gsb\">\n                        <size key=\"minSize\" width=\"22\" height=\"22\"/>\n                        <size key=\"maxSize\" width=\"22\" height=\"22\"/>\n                        <connections>\n                            <action selector=\"toolbarButtonHandler:\" target=\"-2\" id=\"XG6-Jb-CdL\"/>\n                        </connections>\n                    </toolbarItem>\n                    <toolbarItem implicitItemIdentifier=\"17E7D752-54CB-43BA-A631-2CD19CEA653E\" explicitItemIdentifier=\"Update\" label=\"Update\" paletteLabel=\"Update\" tag=\"4\" image=\"PrefsUpdate\" selectable=\"YES\" id=\"pGG-dq-qkU\">\n                        <size key=\"minSize\" width=\"22\" height=\"22\"/>\n                        <size key=\"maxSize\" width=\"22\" height=\"22\"/>\n                        <connections>\n                            <action selector=\"toolbarButtonHandler:\" target=\"-2\" id=\"lEh-OO-GmV\"/>\n                        </connections>\n                    </toolbarItem>\n                </allowedToolbarItems>\n                <defaultToolbarItems>\n                    <toolbarItem reference=\"Twx-TJ-y2Q\"/>\n                    <toolbarItem reference=\"J66-tT-qAf\"/>\n                    <toolbarItem reference=\"k0w-Oi-kwd\"/>\n                    <toolbarItem reference=\"J66-tT-qAf\"/>\n                    <toolbarItem reference=\"rrF-xj-cXp\"/>\n                    <toolbarItem reference=\"J66-tT-qAf\"/>\n                    <toolbarItem reference=\"5li-Ut-Gsb\"/>\n                    <toolbarItem reference=\"J66-tT-qAf\"/>\n                    <toolbarItem reference=\"pGG-dq-qkU\"/>\n                </defaultToolbarItems>\n            </toolbar>\n            <connections>\n                <outlet property=\"delegate\" destination=\"-2\" id=\"0bl-1N-AYu\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"-762\" y=\"545\"/>\n        </window>\n        <customView id=\"378-bj-fYw\" userLabel=\"Rules\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"650\" height=\"429\"/>\n            <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n            <subviews>\n                <button tag=\"1\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"gkd-LL-o86\">\n                    <rect key=\"frame\" x=\"39\" y=\"377\" width=\"29\" height=\"18\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <buttonCell key=\"cell\" type=\"check\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"qBl-9O-n2u\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"menu\" size=\"14\"/>\n                    </buttonCell>\n                    <connections>\n                        <action selector=\"togglePreference:\" target=\"-2\" id=\"hCf-ID-afp\"/>\n                    </connections>\n                </button>\n                <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"IlI-AI-u7J\">\n                    <rect key=\"frame\" x=\"72\" y=\"375\" width=\"510\" height=\"19\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Allow Apple Programs\" id=\"Shu-Wz-4ax\">\n                        <font key=\"font\" size=\"13\" name=\"Menlo-Bold\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" fixedFrame=\"YES\" allowsCharacterPickerTouchBarItem=\"YES\" preferredMaxLayoutWidth=\"471\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Zcd-0q-bOa\">\n                    <rect key=\"frame\" x=\"72\" y=\"350\" width=\"508\" height=\"26\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" title=\"Outgoing connections from Apple-signed programs will be allowed.\" id=\"M8X-n4-v2d\">\n                        <font key=\"font\" size=\"11\" name=\"Menlo-Regular\"/>\n                        <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <button tag=\"2\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"kLX-Ap-3dh\">\n                    <rect key=\"frame\" x=\"39\" y=\"324\" width=\"29\" height=\"18\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <buttonCell key=\"cell\" type=\"check\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"8KA-Aq-zex\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"menu\" size=\"14\"/>\n                    </buttonCell>\n                    <connections>\n                        <action selector=\"togglePreference:\" target=\"-2\" id=\"9Kw-RG-KJy\"/>\n                    </connections>\n                </button>\n                <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Q5L-bq-4ua\">\n                    <rect key=\"frame\" x=\"72\" y=\"322\" width=\"508\" height=\"19\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Allow Already Installed Programs\" id=\"jvT-uI-uNq\">\n                        <font key=\"font\" size=\"13\" name=\"Menlo-Bold\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" fixedFrame=\"YES\" allowsCharacterPickerTouchBarItem=\"YES\" preferredMaxLayoutWidth=\"471\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Hyt-Pl-KUs\">\n                    <rect key=\"frame\" x=\"72\" y=\"297\" width=\"567\" height=\"26\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" title=\"Outgoing connections from currently installed 3rd-party programs will be allowed.\" id=\"6gH-HW-CFe\">\n                        <font key=\"font\" size=\"11\" name=\"Menlo-Regular\"/>\n                        <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <button tag=\"5\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"fQb-j3-FoU\">\n                    <rect key=\"frame\" x=\"39\" y=\"165\" width=\"29\" height=\"18\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <buttonCell key=\"cell\" type=\"check\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"J4Y-ES-3i0\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"menu\" size=\"14\"/>\n                    </buttonCell>\n                    <connections>\n                        <action selector=\"togglePreference:\" target=\"-2\" id=\"Fd0-mP-Sge\"/>\n                    </connections>\n                </button>\n                <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"hUM-gv-uWI\">\n                    <rect key=\"frame\" x=\"72\" y=\"163\" width=\"508\" height=\"19\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Allow Simulator Programs\" id=\"Uqq-dW-xf2\">\n                        <font key=\"font\" size=\"13\" name=\"Menlo-Bold\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" fixedFrame=\"YES\" allowsCharacterPickerTouchBarItem=\"YES\" preferredMaxLayoutWidth=\"471\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ZjJ-WW-3Ir\">\n                    <rect key=\"frame\" x=\"72\" y=\"138\" width=\"554\" height=\"26\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" title=\"Outgoing connections from programs running in the (iOS) simulator will be allowed.\" id=\"e6s-dd-HG6\">\n                        <font key=\"font\" size=\"11\" name=\"Menlo-Regular\"/>\n                        <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <button tag=\"3\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"k2a-YO-A6A\">\n                    <rect key=\"frame\" x=\"39\" y=\"271\" width=\"29\" height=\"18\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <buttonCell key=\"cell\" type=\"check\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"0xC-eE-Mcz\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"menu\" size=\"14\"/>\n                    </buttonCell>\n                    <connections>\n                        <action selector=\"togglePreference:\" target=\"-2\" id=\"hVu-vj-z9l\"/>\n                    </connections>\n                </button>\n                <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"2vI-jc-apL\">\n                    <rect key=\"frame\" x=\"72\" y=\"269\" width=\"510\" height=\"19\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Allow DNS Traffic\" id=\"wED-Z0-197\">\n                        <font key=\"font\" size=\"13\" name=\"Menlo-Bold\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" fixedFrame=\"YES\" allowsCharacterPickerTouchBarItem=\"YES\" preferredMaxLayoutWidth=\"471\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"fg5-Ws-kmD\">\n                    <rect key=\"frame\" x=\"72\" y=\"244\" width=\"508\" height=\"26\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" title=\"All outgoing UDP traffic on port 53 will be allowed.\" id=\"iYm-DO-gHs\">\n                        <font key=\"font\" size=\"11\" name=\"Menlo-Regular\"/>\n                        <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <button tag=\"4\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"iY7-o9-c5m\">\n                    <rect key=\"frame\" x=\"37\" y=\"218\" width=\"29\" height=\"18\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <buttonCell key=\"cell\" type=\"check\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"pbD-7C-Uut\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"menu\" size=\"14\"/>\n                    </buttonCell>\n                    <connections>\n                        <action selector=\"togglePreference:\" target=\"-2\" id=\"JIo-ib-40A\"/>\n                    </connections>\n                </button>\n                <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"xvQ-1T-rZO\">\n                    <rect key=\"frame\" x=\"70\" y=\"216\" width=\"510\" height=\"19\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Allow Localhost Traffic\" id=\"F6g-hE-DiK\">\n                        <font key=\"font\" size=\"13\" name=\"Menlo-Bold\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" fixedFrame=\"YES\" allowsCharacterPickerTouchBarItem=\"YES\" preferredMaxLayoutWidth=\"471\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"3XI-VJ-kgK\">\n                    <rect key=\"frame\" x=\"70\" y=\"191\" width=\"508\" height=\"26\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" title=\"Outgoing connections to localhost will be allowed.\" id=\"caA-Ec-ysj\">\n                        <font key=\"font\" size=\"11\" name=\"Menlo-Regular\"/>\n                        <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <button verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Z2e-jM-Y0P\">\n                    <rect key=\"frame\" x=\"208\" y=\"35\" width=\"233\" height=\"40\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <buttonCell key=\"cell\" type=\"push\" title=\"View Rules\" bezelStyle=\"rounded\" alignment=\"center\" controlSize=\"large\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"Cfj-2E-dIA\">\n                        <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                        <font key=\"font\" size=\"16\" name=\"Menlo-Bold\"/>\n                    </buttonCell>\n                    <connections>\n                        <action selector=\"viewRules:\" target=\"-2\" id=\"PDE-gg-qGI\"/>\n                    </connections>\n                </button>\n            </subviews>\n            <point key=\"canvasLocation\" x=\"-149\" y=\"546.5\"/>\n        </customView>\n        <customView misplaced=\"YES\" id=\"K6i-xr-27e\" userLabel=\"Modes\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"650\" height=\"385\"/>\n            <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n            <subviews>\n                <button tag=\"6\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"4sq-mb-bci\">\n                    <rect key=\"frame\" x=\"39\" y=\"333\" width=\"29\" height=\"18\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <buttonCell key=\"cell\" type=\"check\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"RwL-kA-7QL\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"menu\" size=\"14\"/>\n                    </buttonCell>\n                    <connections>\n                        <action selector=\"togglePreference:\" target=\"-2\" id=\"tpK-Y8-G90\"/>\n                    </connections>\n                </button>\n                <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"xbe-1S-lpy\">\n                    <rect key=\"frame\" x=\"72\" y=\"331\" width=\"510\" height=\"19\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Passive Mode\" id=\"JVI-Or-h0u\">\n                        <font key=\"font\" size=\"13\" name=\"Menlo-Bold\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <button tag=\"7\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Bog-hz-gcd\">\n                    <rect key=\"frame\" x=\"39\" y=\"176\" width=\"29\" height=\"18\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <buttonCell key=\"cell\" type=\"check\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"Aaw-XT-TEt\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"menu\" size=\"14\"/>\n                    </buttonCell>\n                    <connections>\n                        <action selector=\"togglePreference:\" target=\"-2\" id=\"aP4-WS-lmI\"/>\n                    </connections>\n                </button>\n                <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Kjh-jc-STu\">\n                    <rect key=\"frame\" x=\"72\" y=\"174\" width=\"510\" height=\"19\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Block Mode\" id=\"4EN-j2-enV\">\n                        <font key=\"font\" size=\"13\" name=\"Menlo-Bold\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" fixedFrame=\"YES\" allowsCharacterPickerTouchBarItem=\"YES\" preferredMaxLayoutWidth=\"471\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"xaO-g8-rdS\">\n                    <rect key=\"frame\" x=\"72\" y=\"149\" width=\"510\" height=\"26\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" title=\"All traffic routed thru LuLu will be blocked (unless the endpoint is explicitly on the 'Allow' list).\" id=\"SG5-YM-BoV\">\n                        <font key=\"font\" size=\"11\" name=\"Menlo-Regular\"/>\n                        <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <button tag=\"8\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"HeI-XQ-T5H\">\n                    <rect key=\"frame\" x=\"39\" y=\"110\" width=\"29\" height=\"18\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <buttonCell key=\"cell\" type=\"check\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"r4E-e7-bG0\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"menu\" size=\"14\"/>\n                    </buttonCell>\n                    <connections>\n                        <action selector=\"togglePreference:\" target=\"-2\" id=\"1VI-L3-ROB\"/>\n                    </connections>\n                </button>\n                <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"jD1-tF-SsA\">\n                    <rect key=\"frame\" x=\"72\" y=\"108\" width=\"510\" height=\"19\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"No Icon Mode\" id=\"iOJ-Bc-hxG\">\n                        <font key=\"font\" size=\"13\" name=\"Menlo-Bold\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" fixedFrame=\"YES\" allowsCharacterPickerTouchBarItem=\"YES\" preferredMaxLayoutWidth=\"471\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"xXU-nn-zh9\">\n                    <rect key=\"frame\" x=\"72\" y=\"84\" width=\"510\" height=\"26\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" title=\"Run without showing an icon in the status menu bar.\" id=\"bYB-s1-S3f\">\n                        <font key=\"font\" size=\"11\" name=\"Menlo-Regular\"/>\n                        <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" fixedFrame=\"YES\" allowsCharacterPickerTouchBarItem=\"YES\" preferredMaxLayoutWidth=\"471\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"tFB-E4-zbp\">\n                    <rect key=\"frame\" x=\"72\" y=\"319\" width=\"510\" height=\"13\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" title=\"Silently run without alerts, applying existing rules.\" id=\"E0T-Ug-P8f\">\n                        <font key=\"font\" size=\"11\" name=\"Menlo-Regular\"/>\n                        <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <box titlePosition=\"noTitle\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"9ri-c7-k9x\">\n                    <rect key=\"frame\" x=\"74\" y=\"227\" width=\"506\" height=\"86\"/>\n                    <view key=\"contentView\" id=\"7g5-qR-YSr\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"506\" height=\"86\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <popUpButton springLoaded=\"YES\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"CBy-MH-fsc\">\n                                <rect key=\"frame\" x=\"397\" y=\"55\" width=\"96\" height=\"20\"/>\n                                <popUpButtonCell key=\"cell\" type=\"push\" title=\"Allowed\" bezelStyle=\"rounded\" alignment=\"left\" lineBreakMode=\"truncatingTail\" state=\"on\" borderStyle=\"borderAndBezel\" imageScaling=\"proportionallyDown\" inset=\"2\" selectedItem=\"CqC-4v-5d3\" id=\"ssl-E3-3tL\">\n                                    <behavior key=\"behavior\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                    <font key=\"font\" size=\"11\" name=\"Menlo-Regular\"/>\n                                    <menu key=\"menu\" id=\"Ned-2Z-nv8\">\n                                        <items>\n                                            <menuItem title=\"Allowed\" state=\"on\" id=\"CqC-4v-5d3\">\n                                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            </menuItem>\n                                            <menuItem title=\"Blocked\" id=\"mCn-AV-g9h\">\n                                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            </menuItem>\n                                        </items>\n                                    </menu>\n                                </popUpButtonCell>\n                                <constraints>\n                                    <constraint firstAttribute=\"height\" constant=\"20\" id=\"TM7-bg-q1n\"/>\n                                    <constraint firstAttribute=\"width\" constant=\"96\" id=\"oYr-vD-9fC\"/>\n                                </constraints>\n                                <connections>\n                                    <action selector=\"togglePreference:\" target=\"-2\" id=\"4on-EY-CRn\"/>\n                                </connections>\n                            </popUpButton>\n                            <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" fixedFrame=\"YES\" allowsCharacterPickerTouchBarItem=\"YES\" preferredMaxLayoutWidth=\"471\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"t22-Z1-Pfw\">\n                                <rect key=\"frame\" x=\"12\" y=\"52\" width=\"370\" height=\"20\"/>\n                                <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                                <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" title=\"New connections should be be:\" id=\"GsR-9d-5N8\">\n                                    <font key=\"font\" size=\"11\" name=\"Menlo-Regular\"/>\n                                    <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                            <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" fixedFrame=\"YES\" allowsCharacterPickerTouchBarItem=\"YES\" preferredMaxLayoutWidth=\"471\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"7Lm-Wv-aXo\">\n                                <rect key=\"frame\" x=\"12\" y=\"20\" width=\"396\" height=\"14\"/>\n                                <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                                <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" title=\"Rules for new connections should be created?\" id=\"5Wo-JL-Khb\">\n                                    <font key=\"font\" size=\"11\" name=\"Menlo-Regular\"/>\n                                    <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                            <popUpButton springLoaded=\"YES\" verticalHuggingPriority=\"750\" ambiguous=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"24D-f1-OZB\">\n                                <rect key=\"frame\" x=\"397\" y=\"13\" width=\"96\" height=\"25\"/>\n                                <popUpButtonCell key=\"cell\" type=\"push\" title=\"No\" bezelStyle=\"rounded\" alignment=\"left\" lineBreakMode=\"truncatingTail\" state=\"on\" borderStyle=\"borderAndBezel\" imageScaling=\"proportionallyDown\" inset=\"2\" selectedItem=\"JwN-0v-5Uh\" id=\"yFL-Lw-hGA\">\n                                    <behavior key=\"behavior\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                    <font key=\"font\" size=\"11\" name=\"Menlo-Regular\"/>\n                                    <menu key=\"menu\" id=\"MzQ-EA-xSp\">\n                                        <items>\n                                            <menuItem title=\"No\" state=\"on\" id=\"JwN-0v-5Uh\">\n                                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            </menuItem>\n                                            <menuItem title=\"Yes\" id=\"e5A-iH-fS4\">\n                                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            </menuItem>\n                                        </items>\n                                    </menu>\n                                </popUpButtonCell>\n                                <constraints>\n                                    <constraint firstAttribute=\"width\" constant=\"96\" id=\"VxS-g2-40h\"/>\n                                    <constraint firstAttribute=\"height\" constant=\"20\" id=\"sZI-by-YWT\"/>\n                                </constraints>\n                                <connections>\n                                    <action selector=\"togglePreference:\" target=\"-2\" id=\"mIe-8k-8HD\"/>\n                                </connections>\n                            </popUpButton>\n                        </subviews>\n                        <constraints>\n                            <constraint firstAttribute=\"trailing\" secondItem=\"CBy-MH-fsc\" secondAttribute=\"trailing\" constant=\"13\" id=\"j7q-cS-CZ7\"/>\n                            <constraint firstItem=\"CBy-MH-fsc\" firstAttribute=\"top\" secondItem=\"7g5-qR-YSr\" secondAttribute=\"top\" constant=\"11\" id=\"rM8-Yl-CCl\"/>\n                            <constraint firstAttribute=\"trailing\" secondItem=\"24D-f1-OZB\" secondAttribute=\"trailing\" constant=\"13\" id=\"vcN-1H-Azb\"/>\n                        </constraints>\n                    </view>\n                    <constraints>\n                        <constraint firstAttribute=\"height\" constant=\"86\" id=\"rme-hY-C3n\"/>\n                        <constraint firstAttribute=\"width\" constant=\"506\" id=\"vMB-pD-F2d\"/>\n                    </constraints>\n                </box>\n                <button tag=\"9\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"8Y6-5k-ubb\">\n                    <rect key=\"frame\" x=\"39\" y=\"56\" width=\"29\" height=\"18\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <buttonCell key=\"cell\" type=\"check\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"dha-mH-kG4\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"menu\" size=\"14\"/>\n                    </buttonCell>\n                    <connections>\n                        <action selector=\"togglePreference:\" target=\"-2\" id=\"whO-9v-qzu\"/>\n                    </connections>\n                </button>\n                <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"myx-wK-HTz\">\n                    <rect key=\"frame\" x=\"72\" y=\"54\" width=\"510\" height=\"19\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"No VirusTotal Mode\" id=\"wka-xk-z2g\">\n                        <font key=\"font\" size=\"13\" name=\"Menlo-Bold\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" fixedFrame=\"YES\" allowsCharacterPickerTouchBarItem=\"YES\" preferredMaxLayoutWidth=\"471\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Xm8-1J-Md3\">\n                    <rect key=\"frame\" x=\"72\" y=\"41\" width=\"510\" height=\"14\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" title=\"Disable integration with VirusTotal.\" id=\"XTD-vf-hNE\">\n                        <font key=\"font\" size=\"11\" name=\"Menlo-Regular\"/>\n                        <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n            </subviews>\n            <constraints>\n                <constraint firstItem=\"9ri-c7-k9x\" firstAttribute=\"top\" secondItem=\"K6i-xr-27e\" secondAttribute=\"top\" constant=\"72\" id=\"OE3-Lq-DgW\"/>\n                <constraint firstAttribute=\"trailing\" secondItem=\"9ri-c7-k9x\" secondAttribute=\"trailing\" constant=\"20\" id=\"sNO-up-o0t\"/>\n                <constraint firstItem=\"9ri-c7-k9x\" firstAttribute=\"leading\" secondItem=\"K6i-xr-27e\" secondAttribute=\"leading\" constant=\"74\" id=\"xZX-QD-sgA\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"502\" y=\"522.5\"/>\n        </customView>\n        <customView id=\"Nkz-5s-cqG\" userLabel=\"Lists\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"650\" height=\"361\"/>\n            <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n            <subviews>\n                <button tag=\"10\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"NkT-YS-mX8\">\n                    <rect key=\"frame\" x=\"39\" y=\"309\" width=\"29\" height=\"18\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <buttonCell key=\"cell\" type=\"check\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"5NX-ao-MtB\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"menu\" size=\"14\"/>\n                    </buttonCell>\n                    <connections>\n                        <action selector=\"togglePreference:\" target=\"-2\" id=\"LAe-qM-HUb\"/>\n                    </connections>\n                </button>\n                <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"2kS-8f-CMi\">\n                    <rect key=\"frame\" x=\"72\" y=\"307\" width=\"510\" height=\"19\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Allow List:\" id=\"FE3-Li-d3K\">\n                        <font key=\"font\" size=\"13\" name=\"Menlo-Bold\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <button verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"S67-V3-uih\">\n                    <rect key=\"frame\" x=\"446\" y=\"254\" width=\"126\" height=\"32\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <buttonCell key=\"cell\" type=\"push\" title=\"Browse\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"Fut-ad-zCW\">\n                        <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                        <font key=\"font\" size=\"13\" name=\"Menlo-Bold\"/>\n                    </buttonCell>\n                    <connections>\n                        <action selector=\"selectBlockOrAllowList:\" target=\"-2\" id=\"vJp-rf-wVE\"/>\n                    </connections>\n                </button>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"4CH-OQ-Fxj\">\n                    <rect key=\"frame\" x=\"74\" y=\"260\" width=\"360\" height=\"21\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" refusesFirstResponder=\"YES\" sendsActionOnEndEditing=\"YES\" borderStyle=\"bezel\" drawsBackground=\"YES\" id=\"jch-z4-HaH\">\n                        <font key=\"font\" size=\"13\" name=\"Menlo-Regular\"/>\n                        <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <action selector=\"updateBlockList:\" target=\"-2\" id=\"yHB-JK-0Yl\"/>\n                    </connections>\n                </textField>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" fixedFrame=\"YES\" allowsCharacterPickerTouchBarItem=\"YES\" preferredMaxLayoutWidth=\"471\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"RXk-GO-rzE\">\n                    <rect key=\"frame\" x=\"72\" y=\"283\" width=\"510\" height=\"26\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" title=\"Local or remote file, containing endpoints to always allow.\" id=\"7iJ-xR-xDI\">\n                        <font key=\"font\" size=\"11\" name=\"Menlo-Regular\"/>\n                        <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <button tag=\"11\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"jMU-Gf-0go\">\n                    <rect key=\"frame\" x=\"39\" y=\"206\" width=\"29\" height=\"18\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <buttonCell key=\"cell\" type=\"check\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"Xbf-ok-FRs\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"menu\" size=\"14\"/>\n                    </buttonCell>\n                    <connections>\n                        <action selector=\"togglePreference:\" target=\"-2\" id=\"d1j-N2-m72\"/>\n                    </connections>\n                </button>\n                <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"AKI-AF-OVq\">\n                    <rect key=\"frame\" x=\"72\" y=\"204\" width=\"510\" height=\"19\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Block List:\" id=\"Emd-wS-UQh\">\n                        <font key=\"font\" size=\"13\" name=\"Menlo-Bold\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"n5J-8K-UDy\">\n                    <rect key=\"frame\" x=\"74\" y=\"157\" width=\"360\" height=\"21\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" refusesFirstResponder=\"YES\" sendsActionOnEndEditing=\"YES\" borderStyle=\"bezel\" drawsBackground=\"YES\" id=\"cOM-J9-h2z\">\n                        <font key=\"font\" size=\"13\" name=\"Menlo-Regular\"/>\n                        <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <action selector=\"updateBlockList:\" target=\"-2\" id=\"hgI-bs-5Za\"/>\n                    </connections>\n                </textField>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" fixedFrame=\"YES\" allowsCharacterPickerTouchBarItem=\"YES\" preferredMaxLayoutWidth=\"471\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Mkz-oL-YMZ\">\n                    <rect key=\"frame\" x=\"72\" y=\"180\" width=\"510\" height=\"26\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" title=\"Local or remote file, containing endpoints to always block.\" id=\"Bdp-Z8-BhB\">\n                        <font key=\"font\" size=\"11\" name=\"Menlo-Regular\"/>\n                        <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <box fixedFrame=\"YES\" titlePosition=\"noTitle\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ASu-W7-Cac\">\n                    <rect key=\"frame\" x=\"17\" y=\"40\" width=\"616\" height=\"85\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <view key=\"contentView\" id=\"lb7-fh-vLA\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"616\" height=\"85\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" fixedFrame=\"YES\" allowsCharacterPickerTouchBarItem=\"YES\" preferredMaxLayoutWidth=\"471\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"heq-3o-XOl\">\n                                <rect key=\"frame\" x=\"18\" y=\"20\" width=\"572\" height=\"52\"/>\n                                <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                                <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" alignment=\"justified\" id=\"6vU-GO-opk\">\n                                    <font key=\"font\" size=\"11\" name=\"Menlo-Regular\"/>\n                                    <string key=\"title\">Note: When a new connection is made, sometimes only the IP address may be available. In such cases, domains on the allow or block list cannot be matched, which may impact whether a request is blocked or allowed.</string>\n                                    <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                        </subviews>\n                    </view>\n                </box>\n                <button verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"OwS-Bs-2O3\">\n                    <rect key=\"frame\" x=\"446\" y=\"151\" width=\"126\" height=\"32\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <buttonCell key=\"cell\" type=\"push\" title=\"Browse\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"W6X-IU-31r\">\n                        <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                        <font key=\"font\" size=\"13\" name=\"Menlo-Bold\"/>\n                    </buttonCell>\n                    <connections>\n                        <action selector=\"selectBlockOrAllowList:\" target=\"-2\" id=\"M7o-ZO-hj3\"/>\n                    </connections>\n                </button>\n            </subviews>\n            <point key=\"canvasLocation\" x=\"660\" y=\"1066.5\"/>\n        </customView>\n        <customView id=\"1OV-sl-cSe\" userLabel=\"Update\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"650\" height=\"214\"/>\n            <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n            <subviews>\n                <button tag=\"12\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"dml-JS-liI\">\n                    <rect key=\"frame\" x=\"39\" y=\"162\" width=\"29\" height=\"18\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <buttonCell key=\"cell\" type=\"check\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"ljs-bE-JTP\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"menu\" size=\"14\"/>\n                    </buttonCell>\n                    <connections>\n                        <action selector=\"togglePreference:\" target=\"-2\" id=\"YQd-OG-Lhs\"/>\n                    </connections>\n                </button>\n                <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"YB6-Vv-lQu\">\n                    <rect key=\"frame\" x=\"72\" y=\"160\" width=\"510\" height=\"19\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Disable Update Checks\" id=\"z5b-fA-WCk\">\n                        <font key=\"font\" size=\"13\" name=\"Menlo-Bold\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" fixedFrame=\"YES\" allowsCharacterPickerTouchBarItem=\"YES\" preferredMaxLayoutWidth=\"471\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"TmH-6A-xdG\">\n                    <rect key=\"frame\" x=\"72\" y=\"135\" width=\"510\" height=\"26\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" title=\"Do not automatically check for new versions.\" id=\"JV5-cY-ff4\">\n                        <font key=\"font\" size=\"11\" name=\"Menlo-Regular\"/>\n                        <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Oe2-Ye-1s6\">\n                    <rect key=\"frame\" x=\"18\" y=\"20\" width=\"614\" height=\"47\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"center\" id=\"5gt-xh-Ti5\">\n                        <font key=\"font\" size=\"13\" name=\"Menlo-Bold\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <progressIndicator wantsLayer=\"YES\" horizontalHuggingPriority=\"750\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" maxValue=\"100\" displayedWhenStopped=\"NO\" bezeled=\"NO\" indeterminate=\"YES\" style=\"spinning\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"o0T-ra-4H0\">\n                    <rect key=\"frame\" x=\"410\" y=\"78\" width=\"32\" height=\"32\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                </progressIndicator>\n                <button verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Mtn-pi-zIl\">\n                    <rect key=\"frame\" x=\"250\" y=\"78\" width=\"150\" height=\"32\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <buttonCell key=\"cell\" type=\"push\" title=\"Check Now\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"2qr-2x-A3U\">\n                        <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                        <font key=\"font\" size=\"13\" name=\"Menlo-Bold\"/>\n                    </buttonCell>\n                    <connections>\n                        <action selector=\"check4Update:\" target=\"-2\" id=\"GJb-mB-UIz\"/>\n                    </connections>\n                </button>\n            </subviews>\n            <point key=\"canvasLocation\" x=\"1164\" y=\"438\"/>\n        </customView>\n        <customView id=\"IEt-ZT-jGV\" userLabel=\"Profiles\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"650\" height=\"331\"/>\n            <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n            <subviews>\n                <scrollView fixedFrame=\"YES\" autohidesScrollers=\"YES\" horizontalLineScroll=\"24\" horizontalPageScroll=\"10\" verticalLineScroll=\"24\" verticalPageScroll=\"10\" usesPredominantAxisScrolling=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"PeL-yt-XEg\">\n                    <rect key=\"frame\" x=\"20\" y=\"176\" width=\"610\" height=\"135\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <clipView key=\"contentView\" id=\"Qss-Rr-GTS\">\n                        <rect key=\"frame\" x=\"1\" y=\"1\" width=\"608\" height=\"133\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                        <subviews>\n                            <tableView verticalHuggingPriority=\"750\" allowsExpansionToolTips=\"YES\" columnAutoresizingStyle=\"lastColumnOnly\" multipleSelection=\"NO\" emptySelection=\"NO\" autosaveColumns=\"NO\" rowHeight=\"24\" rowSizeStyle=\"automatic\" headerView=\"gpj-Kd-ghc\" viewBased=\"YES\" id=\"b8D-Cq-rd2\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"608\" height=\"105\"/>\n                                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                <size key=\"intercellSpacing\" width=\"17\" height=\"0.0\"/>\n                                <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <color key=\"gridColor\" name=\"gridColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <tableColumns>\n                                    <tableColumn identifier=\"Current\" width=\"91\" minWidth=\"40\" maxWidth=\"1000\" id=\"9ts-yW-4uE\" userLabel=\"Status\">\n                                        <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" title=\"Selected Profile\">\n                                            <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"headerColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </tableHeaderCell>\n                                        <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" title=\"Text Cell\" id=\"EBm-Ds-N9Z\">\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                        <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                        <prototypeCellViews>\n                                            <tableCellView id=\"9bh-ko-hXL\">\n                                                <rect key=\"frame\" x=\"18\" y=\"0.0\" width=\"89\" height=\"24\"/>\n                                                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                                <subviews>\n                                                    <button tag=\"100\" verticalHuggingPriority=\"750\" id=\"9bE-QT-Hhq\">\n                                                        <rect key=\"frame\" x=\"-1\" y=\"2\" width=\"46\" height=\"20\"/>\n                                                        <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                                                        <buttonCell key=\"cell\" type=\"radio\" bezelStyle=\"regularSquare\" imagePosition=\"only\" alignment=\"center\" inset=\"2\" id=\"7is-gp-rlu\">\n                                                            <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                                            <font key=\"font\" metaFont=\"system\"/>\n                                                        </buttonCell>\n                                                        <connections>\n                                                            <action selector=\"switchProfile:\" target=\"-2\" id=\"YkW-NC-aP9\"/>\n                                                        </connections>\n                                                    </button>\n                                                </subviews>\n                                            </tableCellView>\n                                        </prototypeCellViews>\n                                    </tableColumn>\n                                    <tableColumn identifier=\"Name\" width=\"487\" minWidth=\"40\" maxWidth=\"1000\" id=\"GRx-gM-j7j\">\n                                        <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" title=\"Profile Name\">\n                                            <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"headerColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </tableHeaderCell>\n                                        <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" title=\"Text Cell\" id=\"VJZ-pL-oZb\">\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                        <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                        <prototypeCellViews>\n                                            <tableCellView id=\"rQY-Mc-teJ\">\n                                                <rect key=\"frame\" x=\"124\" y=\"0.0\" width=\"484\" height=\"24\"/>\n                                                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                                <subviews>\n                                                    <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"fNG-TE-KSo\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"4\" width=\"304\" height=\"16\"/>\n                                                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" flexibleMinY=\"YES\" flexibleMaxY=\"YES\"/>\n                                                        <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" sendsActionOnEndEditing=\"YES\" title=\"Table View Cell\" id=\"Lrb-j7-fuQ\">\n                                                            <font key=\"font\" usesAppearanceFont=\"YES\"/>\n                                                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                        </textFieldCell>\n                                                    </textField>\n                                                    <button tag=\"101\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"hxj-Ur-U0j\">\n                                                        <rect key=\"frame\" x=\"464\" y=\"2\" width=\"20\" height=\"21\"/>\n                                                        <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                                                        <buttonCell key=\"cell\" type=\"bevel\" bezelStyle=\"regularSquare\" image=\"NSStopProgressFreestandingTemplate\" imagePosition=\"overlaps\" alignment=\"center\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"aMR-uQ-XJ3\">\n                                                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                                            <font key=\"font\" metaFont=\"system\"/>\n                                                        </buttonCell>\n                                                        <connections>\n                                                            <action selector=\"deleteProfile:\" target=\"-2\" id=\"HyF-ag-R4G\"/>\n                                                        </connections>\n                                                    </button>\n                                                </subviews>\n                                                <connections>\n                                                    <outlet property=\"textField\" destination=\"fNG-TE-KSo\" id=\"hmD-Mz-mQ3\"/>\n                                                </connections>\n                                            </tableCellView>\n                                        </prototypeCellViews>\n                                    </tableColumn>\n                                </tableColumns>\n                                <connections>\n                                    <outlet property=\"dataSource\" destination=\"-2\" id=\"PhR-mM-Na9\"/>\n                                    <outlet property=\"delegate\" destination=\"-2\" id=\"AUk-Zu-hLS\"/>\n                                </connections>\n                            </tableView>\n                        </subviews>\n                    </clipView>\n                    <scroller key=\"horizontalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"YES\" id=\"NdL-eS-anO\">\n                        <rect key=\"frame\" x=\"1\" y=\"117\" width=\"608\" height=\"17\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </scroller>\n                    <scroller key=\"verticalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"NO\" id=\"5tc-AD-n0U\">\n                        <rect key=\"frame\" x=\"224\" y=\"17\" width=\"15\" height=\"102\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </scroller>\n                    <tableHeaderView key=\"headerView\" wantsLayer=\"YES\" id=\"gpj-Kd-ghc\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"608\" height=\"28\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </tableHeaderView>\n                </scrollView>\n                <button verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"DdT-jI-lg1\">\n                    <rect key=\"frame\" x=\"235\" y=\"122\" width=\"180\" height=\"40\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <buttonCell key=\"cell\" type=\"push\" title=\"Add Profile\" bezelStyle=\"rounded\" alignment=\"center\" controlSize=\"large\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"ICK-Xr-yt1\">\n                        <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                        <font key=\"font\" size=\"12\" name=\"Menlo-Bold\"/>\n                    </buttonCell>\n                    <connections>\n                        <action selector=\"addProfile:\" target=\"-2\" id=\"UPM-Mu-xbx\"/>\n                    </connections>\n                </button>\n                <box fixedFrame=\"YES\" titlePosition=\"noTitle\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"7Qe-7Y-13Z\">\n                    <rect key=\"frame\" x=\"42\" y=\"43\" width=\"566\" height=\"67\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <view key=\"contentView\" id=\"I9Y-vf-Pty\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"566\" height=\"67\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" fixedFrame=\"YES\" allowsCharacterPickerTouchBarItem=\"YES\" preferredMaxLayoutWidth=\"471\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"z5d-7h-d7r\">\n                                <rect key=\"frame\" x=\"18\" y=\"10\" width=\"522\" height=\"44\"/>\n                                <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                                <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" alignment=\"justified\" id=\"7vn-ff-PJk\">\n                                    <font key=\"font\" size=\"11\" name=\"Menlo-Regular\"/>\n                                    <string key=\"title\">Note: A profile defines a set of rules and settings. Once activated, its settings apply LuLu-wide (and can be modified via LuLu's Settings panes). Any new rules will be added only to that profile's ruleset.</string>\n                                    <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                        </subviews>\n                    </view>\n                </box>\n            </subviews>\n            <point key=\"canvasLocation\" x=\"-137\" y=\"1051.5\"/>\n        </customView>\n        <window title=\"Add Profile\" allowsToolTipsWhenApplicationIsInactive=\"NO\" autorecalculatesKeyViewLoop=\"NO\" hidesOnDeactivate=\"YES\" releasedWhenClosed=\"NO\" visibleAtLaunch=\"NO\" frameAutosaveName=\"\" animationBehavior=\"default\" id=\"Zan-q8-ABi\" customClass=\"NSPanel\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\" closable=\"YES\" miniaturizable=\"YES\" resizable=\"YES\" utility=\"YES\"/>\n            <windowPositionMask key=\"initialPositionMask\" leftStrut=\"YES\" rightStrut=\"YES\" topStrut=\"YES\" bottomStrut=\"YES\"/>\n            <rect key=\"contentRect\" x=\"172\" y=\"98\" width=\"650\" height=\"420\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"1280\" height=\"770\"/>\n            <view key=\"contentView\" id=\"XyO-rJ-3Fe\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"650\" height=\"420\"/>\n                <autoresizingMask key=\"autoresizingMask\"/>\n                <subviews>\n                    <button verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"2Fu-cv-a4Y\">\n                        <rect key=\"frame\" x=\"485\" y=\"13\" width=\"152\" height=\"32\"/>\n                        <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Next\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"wVp-l1-Eac\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nGw\n</string>\n                        </buttonCell>\n                        <connections>\n                            <action selector=\"continueProfileButtonHandler:\" target=\"-2\" id=\"stw-RZ-KnT\"/>\n                        </connections>\n                    </button>\n                    <button verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"5DW-XQ-eZC\">\n                        <rect key=\"frame\" x=\"13\" y=\"13\" width=\"76\" height=\"32\"/>\n                        <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Cancel\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"5Fx-eu-v3J\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nGw\n</string>\n                        </buttonCell>\n                        <connections>\n                            <action selector=\"cancelProfileButtonHandler:\" target=\"-2\" id=\"gFh-og-NyL\"/>\n                        </connections>\n                    </button>\n                </subviews>\n            </view>\n            <point key=\"canvasLocation\" x=\"1164\" y=\"1303\"/>\n        </window>\n        <customView id=\"6M4-YG-28h\" userLabel=\"Add Profile Name\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"650\" height=\"194\"/>\n            <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n            <subviews>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ccA-pL-ZcZ\">\n                    <rect key=\"frame\" x=\"233\" y=\"40\" width=\"185\" height=\"21\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" borderStyle=\"bezel\" placeholderString=\"Profile Name\" drawsBackground=\"YES\" id=\"I4i-8n-Kep\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <box fixedFrame=\"YES\" titlePosition=\"noTitle\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"nvR-6A-SPC\">\n                    <rect key=\"frame\" x=\"17\" y=\"102\" width=\"616\" height=\"76\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <view key=\"contentView\" id=\"JDe-ju-zgJ\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"616\" height=\"76\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" fixedFrame=\"YES\" allowsCharacterPickerTouchBarItem=\"YES\" preferredMaxLayoutWidth=\"471\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"lCl-XG-Nab\">\n                                <rect key=\"frame\" x=\"18\" y=\"11\" width=\"522\" height=\"52\"/>\n                                <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                                <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" alignment=\"justified\" id=\"d79-kw-Ala\">\n                                    <font key=\"font\" size=\"11\" name=\"Menlo-Regular\"/>\n                                    <string key=\"title\">First create a name for your profile. \n\nThen click \"Next\" to configure the settings for your new profile.</string>\n                                    <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                        </subviews>\n                    </view>\n                </box>\n                <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ryF-HO-Ncf\">\n                    <rect key=\"frame\" x=\"43\" y=\"43\" width=\"184\" height=\"15\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" lineBreakMode=\"clipping\" alignment=\"right\" title=\"Profile Name:\" id=\"kZA-kY-nGm\">\n                        <font key=\"font\" size=\"13\" name=\"Menlo-Bold\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n            </subviews>\n            <point key=\"canvasLocation\" x=\"445\" y=\"1240\"/>\n        </customView>\n    </objects>\n    <resources>\n        <image name=\"NSStopProgressFreestandingTemplate\" width=\"20\" height=\"20\"/>\n        <image name=\"PrefsList\" width=\"128\" height=\"128\"/>\n        <image name=\"PrefsMode\" width=\"72\" height=\"72\"/>\n        <image name=\"PrefsProfiles\" width=\"32\" height=\"32\"/>\n        <image name=\"PrefsRules\" width=\"72\" height=\"72\"/>\n        <image name=\"PrefsUpdate\" width=\"72\" height=\"72\"/>\n    </resources>\n</document>\n"
  },
  {
    "path": "LuLu/App/Base.lproj/Rules.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"24128\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"24128\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"RulesWindowController\">\n            <connections>\n                <outlet property=\"addRuleButton\" destination=\"XnJ-SV-lDg\" id=\"YqK-bz-bc0\"/>\n                <outlet property=\"addRuleLabel\" destination=\"eUD-fD-sWd\" id=\"BHL-mp-mNT\"/>\n                <outlet property=\"filterBox\" destination=\"6hG-3v-G35\" id=\"fzu-Bv-orq\"/>\n                <outlet property=\"loadingRules\" destination=\"VUa-5Z-QAG\" id=\"aLz-sm-xVQ\"/>\n                <outlet property=\"loadingRulesSpinner\" destination=\"XFi-AG-WZ4\" id=\"aaT-3y-LEG\"/>\n                <outlet property=\"outlineView\" destination=\"ass-Hi-FMe\" id=\"VsR-Ac-HKo\"/>\n                <outlet property=\"rulesViewSelector\" destination=\"mfH-zV-Que\" id=\"xcX-Sf-HLy\"/>\n                <outlet property=\"toolbar\" destination=\"VgN-2b-k77\" id=\"SSB-SZ-3tL\"/>\n                <outlet property=\"view\" destination=\"se5-gp-TjO\" id=\"wqw-Gz-fhe\"/>\n                <outlet property=\"window\" destination=\"F0z-JX-Cv5\" id=\"gIp-Ho-8D9\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <window identifier=\"Rules\" title=\"LuLu Rules\" allowsToolTipsWhenApplicationIsInactive=\"NO\" autorecalculatesKeyViewLoop=\"NO\" releasedWhenClosed=\"NO\" animationBehavior=\"default\" id=\"F0z-JX-Cv5\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\" closable=\"YES\" miniaturizable=\"YES\" resizable=\"YES\"/>\n            <rect key=\"contentRect\" x=\"913\" y=\"419\" width=\"1020\" height=\"700\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"3440\" height=\"1410\"/>\n            <value key=\"minSize\" type=\"size\" width=\"1020\" height=\"400\"/>\n            <view key=\"contentView\" wantsLayer=\"YES\" misplaced=\"YES\" id=\"se5-gp-TjO\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"1020\" height=\"700\"/>\n                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                <userGuides>\n                    <userLayoutGuide location=\"995\" affinity=\"minX\"/>\n                </userGuides>\n                <subviews>\n                    <scrollView fixedFrame=\"YES\" autohidesScrollers=\"YES\" horizontalLineScroll=\"52\" horizontalPageScroll=\"10\" verticalLineScroll=\"52\" verticalPageScroll=\"10\" usesPredominantAxisScrolling=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"tn9-NJ-2RM\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"46\" width=\"1021\" height=\"655\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <clipView key=\"contentView\" id=\"6Xv-R4-m4F\">\n                            <rect key=\"frame\" x=\"1\" y=\"1\" width=\"1019\" height=\"653\"/>\n                            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                            <subviews>\n                                <outlineView verticalHuggingPriority=\"750\" allowsExpansionToolTips=\"YES\" columnAutoresizingStyle=\"firstColumnOnly\" alternatingRowBackgroundColors=\"YES\" columnReordering=\"NO\" multipleSelection=\"NO\" autosaveColumns=\"NO\" rowHeight=\"50\" rowSizeStyle=\"automatic\" headerView=\"0ZG-mg-rCP\" viewBased=\"YES\" indentationPerLevel=\"8\" outlineTableColumn=\"Iaf-If-UX3\" id=\"ass-Hi-FMe\" customClass=\"RulesTable\">\n                                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"1019\" height=\"628\"/>\n                                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                    <size key=\"intercellSpacing\" width=\"3\" height=\"2\"/>\n                                    <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"gridColor\" name=\"gridColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <tableColumns>\n                                        <tableColumn width=\"750\" minWidth=\"750\" maxWidth=\"3.4028234663852886e+38\" id=\"Iaf-If-UX3\" userLabel=\"Main\">\n                                            <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"left\">\n                                                <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                            </tableHeaderCell>\n                                            <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" alignment=\"left\" title=\"Text Cell\" id=\"zq7-2E-zbT\">\n                                                <font key=\"font\" metaFont=\"system\"/>\n                                                <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            </textFieldCell>\n                                            <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\"/>\n                                            <prototypeCellViews>\n                                                <tableCellView identifier=\"processCell\" id=\"hYC-a4-Gp3\" userLabel=\"Process\">\n                                                    <rect key=\"frame\" x=\"1\" y=\"1\" width=\"755\" height=\"50\"/>\n                                                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                                    <subviews>\n                                                        <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" tag=\"100\" textCompletion=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"bkx-JF-q5i\">\n                                                            <rect key=\"frame\" x=\"41\" y=\"20\" width=\"713\" height=\"20\"/>\n                                                            <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" allowsUndo=\"NO\" sendsActionOnEndEditing=\"YES\" title=\"Item Name\" id=\"7zm-Uo-lwv\">\n                                                                <font key=\"font\" size=\"17\" name=\"Menlo-Bold\"/>\n                                                                <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                            </textFieldCell>\n                                                        </textField>\n                                                        <imageView fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"N20-23-Uhm\">\n                                                            <rect key=\"frame\" x=\"3\" y=\"8\" width=\"32\" height=\"32\"/>\n                                                            <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                                                            <imageCell key=\"cell\" refusesFirstResponder=\"YES\" alignment=\"left\" imageScaling=\"proportionallyDown\" image=\"NSColorPanel\" id=\"qD1-Wa-myu\"/>\n                                                        </imageView>\n                                                        <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" tag=\"101\" allowsCharacterPickerTouchBarItem=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Eh8-4j-zJP\">\n                                                            <rect key=\"frame\" x=\"41\" y=\"5\" width=\"713\" height=\"13\"/>\n                                                            <textFieldCell key=\"cell\" lineBreakMode=\"truncatingMiddle\" selectable=\"YES\" allowsUndo=\"NO\" sendsActionOnEndEditing=\"YES\" title=\"item details...\" id=\"qbv-z3-4PI\">\n                                                                <font key=\"font\" size=\"11\" name=\"Menlo-Regular\"/>\n                                                                <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                            </textFieldCell>\n                                                        </textField>\n                                                    </subviews>\n                                                    <constraints>\n                                                        <constraint firstAttribute=\"bottom\" secondItem=\"Eh8-4j-zJP\" secondAttribute=\"bottom\" constant=\"5\" id=\"4HF-9l-vFE\"/>\n                                                        <constraint firstAttribute=\"trailing\" secondItem=\"bkx-JF-q5i\" secondAttribute=\"trailing\" constant=\"3\" id=\"DK8-7A-WGn\"/>\n                                                        <constraint firstItem=\"Eh8-4j-zJP\" firstAttribute=\"top\" secondItem=\"bkx-JF-q5i\" secondAttribute=\"bottom\" constant=\"2\" id=\"MBl-IV-KYy\"/>\n                                                        <constraint firstItem=\"bkx-JF-q5i\" firstAttribute=\"leading\" secondItem=\"hYC-a4-Gp3\" secondAttribute=\"leading\" constant=\"43\" id=\"Mbc-nL-eRZ\"/>\n                                                        <constraint firstItem=\"Eh8-4j-zJP\" firstAttribute=\"leading\" secondItem=\"hYC-a4-Gp3\" secondAttribute=\"leading\" constant=\"43\" id=\"NLQ-rO-LG8\"/>\n                                                        <constraint firstAttribute=\"trailing\" secondItem=\"Eh8-4j-zJP\" secondAttribute=\"trailing\" constant=\"3\" id=\"ZdC-qM-pHV\"/>\n                                                        <constraint firstItem=\"bkx-JF-q5i\" firstAttribute=\"top\" secondItem=\"hYC-a4-Gp3\" secondAttribute=\"top\" constant=\"10\" id=\"bOf-Op-7zO\"/>\n                                                        <constraint firstItem=\"Eh8-4j-zJP\" firstAttribute=\"top\" secondItem=\"bkx-JF-q5i\" secondAttribute=\"bottom\" constant=\"2\" id=\"udt-0d-MNx\"/>\n                                                    </constraints>\n                                                    <connections>\n                                                        <outlet property=\"imageView\" destination=\"N20-23-Uhm\" id=\"wZA-z1-x7L\"/>\n                                                        <outlet property=\"textField\" destination=\"bkx-JF-q5i\" id=\"cbO-X8-NpB\"/>\n                                                    </connections>\n                                                </tableCellView>\n                                                <tableCellView identifier=\"simpleCell\" id=\"Tec-Zl-6cm\" userLabel=\"Connection\" customClass=\"CustomTableCellView\">\n                                                    <rect key=\"frame\" x=\"1\" y=\"53\" width=\"755\" height=\"50\"/>\n                                                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                                    <subviews>\n                                                        <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" textCompletion=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"jpF-QT-jfh\">\n                                                            <rect key=\"frame\" x=\"1\" y=\"13\" width=\"753\" height=\"20\"/>\n                                                            <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" allowsUndo=\"NO\" sendsActionOnEndEditing=\"YES\" title=\"connection info\" id=\"tZf-9e-yHh\">\n                                                                <font key=\"font\" size=\"17\" name=\"Menlo-Regular\"/>\n                                                                <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                            </textFieldCell>\n                                                        </textField>\n                                                    </subviews>\n                                                    <constraints>\n                                                        <constraint firstAttribute=\"trailing\" secondItem=\"jpF-QT-jfh\" secondAttribute=\"trailing\" constant=\"3\" id=\"Mf6-7V-C48\"/>\n                                                        <constraint firstItem=\"jpF-QT-jfh\" firstAttribute=\"leading\" secondItem=\"Tec-Zl-6cm\" secondAttribute=\"leading\" constant=\"3\" id=\"emp-cE-Z8y\"/>\n                                                        <constraint firstItem=\"jpF-QT-jfh\" firstAttribute=\"top\" secondItem=\"Tec-Zl-6cm\" secondAttribute=\"top\" constant=\"17\" id=\"opg-Gi-wb1\"/>\n                                                    </constraints>\n                                                    <connections>\n                                                        <outlet property=\"textField\" destination=\"jpF-QT-jfh\" id=\"NNr-pk-0TP\"/>\n                                                    </connections>\n                                                </tableCellView>\n                                            </prototypeCellViews>\n                                        </tableColumn>\n                                        <tableColumn editable=\"NO\" width=\"250\" minWidth=\"250\" maxWidth=\"250\" id=\"mQo-bf-aNx\">\n                                            <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"left\" title=\" Rule\">\n                                                <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"calibratedWhite\"/>\n                                            </tableHeaderCell>\n                                            <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" alignment=\"left\" title=\"Text Cell\" id=\"BsU-Gh-mch\">\n                                                <font key=\"font\" metaFont=\"system\"/>\n                                                <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            </textFieldCell>\n                                            <prototypeCellViews>\n                                                <tableCellView identifier=\"ruleCell\" id=\"5sm-If-Eqg\" customClass=\"CustomTableCellView\">\n                                                    <rect key=\"frame\" x=\"759\" y=\"1\" width=\"254\" height=\"54\"/>\n                                                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                                    <subviews>\n                                                        <textField focusRingType=\"none\" horizontalHuggingPriority=\"249\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" fixedFrame=\"YES\" tag=\"100\" allowsCharacterPickerTouchBarItem=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"GQ2-Ny-NHf\">\n                                                            <rect key=\"frame\" x=\"35\" y=\"16\" width=\"189\" height=\"20\"/>\n                                                            <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                                                            <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" sendsActionOnEndEditing=\"YES\" id=\"fZ4-hz-z9B\">\n                                                                <font key=\"font\" size=\"13\" name=\"Menlo-Regular\"/>\n                                                                <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                            </textFieldCell>\n                                                        </textField>\n                                                        <imageView fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Py6-88-hfn\">\n                                                            <rect key=\"frame\" x=\"3\" y=\"16\" width=\"24\" height=\"23\"/>\n                                                            <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                                                            <imageCell key=\"cell\" refusesFirstResponder=\"YES\" alignment=\"left\" imageScaling=\"proportionallyUpOrDown\" id=\"TNE-FM-Q4H\"/>\n                                                        </imageView>\n                                                        <button tag=\"110\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ZYK-WR-Jeh\">\n                                                            <rect key=\"frame\" x=\"217\" y=\"9\" width=\"30\" height=\"40\"/>\n                                                            <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                                                            <buttonCell key=\"cell\" type=\"bevel\" bezelStyle=\"regularSquare\" image=\"NSTouchBarTextListTemplate\" imagePosition=\"overlaps\" alignment=\"center\" controlSize=\"large\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"CJy-ZW-Yu6\">\n                                                                <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                                                <font key=\"font\" metaFont=\"system\"/>\n                                                            </buttonCell>\n                                                            <connections>\n                                                                <action selector=\"showRuleMenu:\" target=\"-2\" id=\"xeK-Jj-5mh\"/>\n                                                            </connections>\n                                                        </button>\n                                                    </subviews>\n                                                    <connections>\n                                                        <outlet property=\"imageView\" destination=\"Py6-88-hfn\" id=\"zEs-fw-NDI\"/>\n                                                        <outlet property=\"textField\" destination=\"GQ2-Ny-NHf\" id=\"RD0-Id-ASM\"/>\n                                                    </connections>\n                                                </tableCellView>\n                                            </prototypeCellViews>\n                                        </tableColumn>\n                                    </tableColumns>\n                                    <connections>\n                                        <outlet property=\"dataSource\" destination=\"-2\" id=\"w3L-rC-1aY\"/>\n                                        <outlet property=\"delegate\" destination=\"-2\" id=\"Crv-Lz-nQK\"/>\n                                    </connections>\n                                </outlineView>\n                            </subviews>\n                        </clipView>\n                        <scroller key=\"horizontalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"YES\" id=\"djS-lX-Nkf\">\n                            <rect key=\"frame\" x=\"1\" y=\"637\" width=\"1019\" height=\"17\"/>\n                            <autoresizingMask key=\"autoresizingMask\"/>\n                        </scroller>\n                        <scroller key=\"verticalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"NO\" id=\"Ud6-Ad-xqt\">\n                            <rect key=\"frame\" x=\"224\" y=\"17\" width=\"15\" height=\"102\"/>\n                            <autoresizingMask key=\"autoresizingMask\"/>\n                        </scroller>\n                        <tableHeaderView key=\"headerView\" wantsLayer=\"YES\" id=\"0ZG-mg-rCP\">\n                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"1019\" height=\"25\"/>\n                            <autoresizingMask key=\"autoresizingMask\"/>\n                        </tableHeaderView>\n                    </scrollView>\n                    <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"eUD-fD-sWd\">\n                        <rect key=\"frame\" x=\"830\" y=\"14\" width=\"149\" height=\"15\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"width\" constant=\"145\" id=\"Mxq-DQ-euD\"/>\n                            <constraint firstAttribute=\"height\" constant=\"15\" id=\"eie-Hn-5SE\"/>\n                        </constraints>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Add Rule\" id=\"wLE-Rk-GOf\">\n                            <font key=\"font\" size=\"13\" name=\"Menlo-Bold\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"VUa-5Z-QAG\" userLabel=\"Overlay\" customClass=\"NSVisualEffectView\">\n                        <rect key=\"frame\" x=\"258\" y=\"238\" width=\"500\" height=\"200\"/>\n                        <subviews>\n                            <progressIndicator wantsLayer=\"YES\" horizontalHuggingPriority=\"750\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" maxValue=\"100\" displayedWhenStopped=\"NO\" bezeled=\"NO\" indeterminate=\"YES\" style=\"spinning\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"XFi-AG-WZ4\">\n                                <rect key=\"frame\" x=\"234\" y=\"84\" width=\"32\" height=\"32\"/>\n                                <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                            </progressIndicator>\n                            <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" setsMaxLayoutWidthAtFirstLayout=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"FKP-Dh-JqV\" userLabel=\"loading data\">\n                                <rect key=\"frame\" x=\"44\" y=\"44\" width=\"413\" height=\"30\"/>\n                                <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                                <textFieldCell key=\"cell\" allowsUndo=\"NO\" sendsActionOnEndEditing=\"YES\" alignment=\"center\" title=\"(re)loading rules...\" id=\"vD6-Bk-elz\">\n                                    <font key=\"font\" size=\"13\" name=\"Menlo-Bold\"/>\n                                    <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                        </subviews>\n                        <constraints>\n                            <constraint firstAttribute=\"height\" constant=\"200\" id=\"5Rn-vq-nlT\"/>\n                            <constraint firstAttribute=\"width\" constant=\"500\" id=\"LCd-m8-ewV\"/>\n                        </constraints>\n                    </customView>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"QQG-tM-Qn1\" userLabel=\"LuLu Button\">\n                        <rect key=\"frame\" x=\"453\" y=\"3\" width=\"110\" height=\"38\"/>\n                        <buttonCell key=\"cell\" type=\"bevel\" bezelStyle=\"rounded\" image=\"LuLuText\" imagePosition=\"overlaps\" alignment=\"center\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"L9P-uv-Ruu\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                        </buttonCell>\n                        <constraints>\n                            <constraint firstAttribute=\"height\" constant=\"38\" id=\"Xte-zr-TuP\"/>\n                            <constraint firstAttribute=\"width\" constant=\"110\" id=\"eFM-io-YLf\"/>\n                        </constraints>\n                        <connections>\n                            <action selector=\"openHomePage:\" target=\"-2\" id=\"u6B-xt-jUH\"/>\n                        </connections>\n                    </button>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"XnJ-SV-lDg\">\n                        <rect key=\"frame\" x=\"985\" y=\"11\" width=\"21\" height=\"21\"/>\n                        <buttonCell key=\"cell\" type=\"smallSquare\" bezelStyle=\"smallSquare\" image=\"NSAddTemplate\" imagePosition=\"overlaps\" alignment=\"center\" lineBreakMode=\"truncatingTail\" state=\"on\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"w4Y-Vg-33Z\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                        </buttonCell>\n                        <constraints>\n                            <constraint firstAttribute=\"height\" constant=\"19\" id=\"dB8-Rh-IY3\"/>\n                            <constraint firstAttribute=\"width\" constant=\"21\" id=\"xp2-P3-CWL\"/>\n                        </constraints>\n                        <connections>\n                            <action selector=\"addRule:\" target=\"-2\" id=\"rDo-9C-hpS\"/>\n                        </connections>\n                    </button>\n                </subviews>\n                <constraints>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"eUD-fD-sWd\" secondAttribute=\"bottom\" constant=\"14\" id=\"8Ef-ds-Jg0\"/>\n                    <constraint firstItem=\"VUa-5Z-QAG\" firstAttribute=\"centerY\" secondItem=\"se5-gp-TjO\" secondAttribute=\"centerY\" id=\"DAy-mh-4L6\"/>\n                    <constraint firstItem=\"XnJ-SV-lDg\" firstAttribute=\"leading\" secondItem=\"eUD-fD-sWd\" secondAttribute=\"trailing\" constant=\"8\" id=\"M9P-GI-0H0\"/>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"XnJ-SV-lDg\" secondAttribute=\"bottom\" constant=\"12\" id=\"ONy-4k-MUE\"/>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"QQG-tM-Qn1\" secondAttribute=\"bottom\" constant=\"3\" id=\"co7-PF-80H\"/>\n                    <constraint firstItem=\"VUa-5Z-QAG\" firstAttribute=\"centerX\" secondItem=\"se5-gp-TjO\" secondAttribute=\"centerX\" id=\"hpP-ol-ynU\"/>\n                    <constraint firstItem=\"QQG-tM-Qn1\" firstAttribute=\"centerX\" secondItem=\"se5-gp-TjO\" secondAttribute=\"centerX\" id=\"k0D-o6-es6\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"XnJ-SV-lDg\" secondAttribute=\"trailing\" constant=\"10\" id=\"kg7-UZ-Jn8\"/>\n                </constraints>\n            </view>\n            <toolbar key=\"toolbar\" implicitIdentifier=\"BAC88DC5-D2D2-4ADF-B070-99F6A091AAC8\" autosavesConfiguration=\"NO\" showsBaselineSeparator=\"NO\" displayMode=\"iconAndLabel\" sizeMode=\"regular\" id=\"VgN-2b-k77\">\n                <allowedToolbarItems>\n                    <toolbarItem implicitItemIdentifier=\"NSToolbarSpaceItem\" id=\"1EK-dM-lw3\"/>\n                    <toolbarItem implicitItemIdentifier=\"NSToolbarFlexibleSpaceItem\" id=\"csB-HX-Bm6\"/>\n                    <toolbarItem implicitItemIdentifier=\"6A861BC3-0977-42BD-857D-D0D8C06EB403\" label=\"\" paletteLabel=\"\" tag=\"5\" id=\"laZ-lE-1iU\">\n                        <nil key=\"toolTip\"/>\n                        <size key=\"minSize\" width=\"96\" height=\"22\"/>\n                        <size key=\"maxSize\" width=\"207\" height=\"22\"/>\n                        <searchField key=\"view\" identifier=\"abc\" wantsLayer=\"YES\" focusRingType=\"none\" verticalHuggingPriority=\"750\" tag=\"5\" textCompletion=\"NO\" id=\"6hG-3v-G35\">\n                            <rect key=\"frame\" x=\"0.0\" y=\"14\" width=\"189\" height=\"22\"/>\n                            <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                            <searchFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" borderStyle=\"bezel\" identifier=\"def\" placeholderString=\"Filter Rules\" usesSingleLineMode=\"YES\" bezelStyle=\"round\" id=\"DWG-ck-lDk\">\n                                <font key=\"font\" metaFont=\"system\"/>\n                                <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <accessibility identifier=\"def\"/>\n                            </searchFieldCell>\n                            <accessibility identifier=\"abc\"/>\n                            <connections>\n                                <action selector=\"filterBoxHandler:\" target=\"-2\" id=\"Kvk-ly-KDr\"/>\n                                <outlet property=\"delegate\" destination=\"-2\" id=\"V1g-ox-J2j\"/>\n                            </connections>\n                        </searchField>\n                    </toolbarItem>\n                    <toolbarItem implicitItemIdentifier=\"D6A4E192-28DB-485F-B968-54E2C252CF2F\" label=\"\" paletteLabel=\"\" title=\"All Rules\" sizingBehavior=\"auto\" id=\"2FE-FA-0jJ\">\n                        <nil key=\"toolTip\"/>\n                        <popUpButton key=\"view\" verticalHuggingPriority=\"750\" id=\"mfH-zV-Que\" userLabel=\"Rule View Selector\">\n                            <rect key=\"frame\" x=\"0.0\" y=\"14\" width=\"180\" height=\"25\"/>\n                            <autoresizingMask key=\"autoresizingMask\"/>\n                            <popUpButtonCell key=\"cell\" type=\"roundTextured\" title=\"All Rules\" bezelStyle=\"texturedRounded\" alignment=\"left\" lineBreakMode=\"truncatingTail\" state=\"on\" borderStyle=\"border\" tag=\"-1\" imageScaling=\"proportionallyDown\" inset=\"2\" selectedItem=\"omZ-DL-6R7\" id=\"qeh-fO-uzj\">\n                                <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                <font key=\"font\" metaFont=\"message\"/>\n                                <menu key=\"menu\" id=\"5Wl-5r-JnV\">\n                                    <items>\n                                        <menuItem title=\"All Rules\" state=\"on\" tag=\"-1\" id=\"omZ-DL-6R7\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                        </menuItem>\n                                        <menuItem title=\"Default Rules\" id=\"rEm-hF-r0T\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                        </menuItem>\n                                        <menuItem title=\"Apple Rules\" tag=\"1\" id=\"qNT-HP-XkH\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                        </menuItem>\n                                        <menuItem title=\"3rd-party Rules\" tag=\"2\" id=\"YzL-Xb-QI1\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                        </menuItem>\n                                        <menuItem title=\"User-created Rules\" tag=\"3\" id=\"cvb-ds-FcC\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                        </menuItem>\n                                        <menuItem title=\"Passively-created Rules\" tag=\"4\" id=\"b9m-wt-VZa\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                        </menuItem>\n                                        <menuItem title=\"Recent Rules\" tag=\"5\" id=\"e4i-1F-tjh\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                                <connections>\n                                    <action selector=\"rulesViewSelectorHandler:\" target=\"-2\" id=\"GJq-H1-tUn\"/>\n                                </connections>\n                            </popUpButtonCell>\n                        </popUpButton>\n                    </toolbarItem>\n                    <toolbarItem implicitItemIdentifier=\"09995CD8-BDB2-42E3-8A29-F4F79BEBE790\" label=\"Custom View\" paletteLabel=\"Custom View\" sizingBehavior=\"auto\" id=\"F7G-1t-415\">\n                        <nil key=\"toolTip\"/>\n                        <textField key=\"view\" focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" id=\"RyV-HD-obr\">\n                            <rect key=\"frame\" x=\"20\" y=\"14\" width=\"37\" height=\"16\"/>\n                            <autoresizingMask key=\"autoresizingMask\"/>\n                            <textFieldCell key=\"cell\" lineBreakMode=\"clipping\" title=\"Label\" id=\"2yS-Gr-1bI\">\n                                <font key=\"font\" usesAppearanceFont=\"YES\"/>\n                                <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            </textFieldCell>\n                        </textField>\n                    </toolbarItem>\n                </allowedToolbarItems>\n                <defaultToolbarItems>\n                    <toolbarItem reference=\"2FE-FA-0jJ\"/>\n                    <toolbarItem reference=\"csB-HX-Bm6\"/>\n                    <toolbarItem reference=\"laZ-lE-1iU\"/>\n                </defaultToolbarItems>\n            </toolbar>\n            <connections>\n                <outlet property=\"delegate\" destination=\"-2\" id=\"0bl-1N-AYu\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"-46\" y=\"418\"/>\n        </window>\n    </objects>\n    <resources>\n        <image name=\"LuLuText\" width=\"1268\" height=\"385\"/>\n        <image name=\"NSAddTemplate\" width=\"18\" height=\"16\"/>\n        <image name=\"NSColorPanel\" width=\"32\" height=\"32\"/>\n        <image name=\"NSTouchBarTextListTemplate\" width=\"21\" height=\"14\"/>\n    </resources>\n</document>\n"
  },
  {
    "path": "LuLu/App/Base.lproj/StartupWindowController.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"23727\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"23727\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"StartupWindowController\">\n            <connections>\n                <outlet property=\"activityIndicator\" destination=\"b1w-5W-ayX\" id=\"P5e-PO-Ozi\"/>\n                <outlet property=\"spinner\" destination=\"b1w-5W-ayX\" id=\"DfC-7g-m9s\"/>\n                <outlet property=\"versionWarning\" destination=\"Kml-Fj-cfr\" id=\"xov-Fj-mRO\"/>\n                <outlet property=\"window\" destination=\"F0z-JX-Cv5\" id=\"gIp-Ho-8D9\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <window allowsToolTipsWhenApplicationIsInactive=\"NO\" autorecalculatesKeyViewLoop=\"NO\" restorable=\"NO\" releasedWhenClosed=\"NO\" visibleAtLaunch=\"NO\" animationBehavior=\"default\" id=\"F0z-JX-Cv5\">\n            <windowStyleMask key=\"styleMask\" texturedBackground=\"YES\"/>\n            <windowPositionMask key=\"initialPositionMask\" leftStrut=\"YES\" rightStrut=\"YES\" topStrut=\"YES\" bottomStrut=\"YES\"/>\n            <rect key=\"contentRect\" x=\"196\" y=\"240\" width=\"523\" height=\"280\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"3440\" height=\"1415\"/>\n            <view key=\"contentView\" id=\"se5-gp-TjO\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"523\" height=\"280\"/>\n                <autoresizingMask key=\"autoresizingMask\"/>\n                <subviews>\n                    <progressIndicator wantsLayer=\"YES\" horizontalHuggingPriority=\"750\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" maxValue=\"100\" bezeled=\"NO\" indeterminate=\"YES\" style=\"spinning\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"b1w-5W-ayX\">\n                        <rect key=\"frame\" x=\"175\" y=\"80\" width=\"32\" height=\"32\"/>\n                        <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    </progressIndicator>\n                    <imageView horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"fgM-lv-GeJ\">\n                        <rect key=\"frame\" x=\"20\" y=\"100\" width=\"114\" height=\"123\"/>\n                        <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                        <imageCell key=\"cell\" refusesFirstResponder=\"YES\" alignment=\"left\" imageScaling=\"proportionallyDown\" image=\"Icon\" id=\"bCU-0f-ff8\"/>\n                    </imageView>\n                    <imageView horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"K52-9g-sjn\">\n                        <rect key=\"frame\" x=\"177\" y=\"128\" width=\"184\" height=\"67\"/>\n                        <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                        <imageCell key=\"cell\" refusesFirstResponder=\"YES\" alignment=\"left\" imageScaling=\"proportionallyDown\" image=\"LuLuText\" id=\"WRg-I2-vkK\"/>\n                    </imageView>\n                    <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"10s-e1-hEh\">\n                        <rect key=\"frame\" x=\"216\" y=\"79\" width=\"289\" height=\"33\"/>\n                        <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                        <textFieldCell key=\"cell\" lineBreakMode=\"clipping\" title=\"Now starting up...\" id=\"tj8-5e-Vlc\">\n                            <font key=\"font\" size=\"24\" name=\"AvenirNextCondensed-Regular\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Kml-Fj-cfr\">\n                        <rect key=\"frame\" x=\"18\" y=\"25\" width=\"487\" height=\"30\"/>\n                        <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                        <textFieldCell key=\"cell\" allowsUndo=\"NO\" alignment=\"center\" title=\"Note: LuLu works best on macOS 15.3+, as Apple fixed bugs affecting network stability. \" id=\"XsZ-6a-7Rk\">\n                            <font key=\"font\" size=\"13\" name=\"Menlo-Regular\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                </subviews>\n            </view>\n            <connections>\n                <outlet property=\"delegate\" destination=\"-2\" id=\"0bl-1N-AYu\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"216.5\" y=\"-204\"/>\n        </window>\n    </objects>\n    <resources>\n        <image name=\"Icon\" width=\"144\" height=\"144\"/>\n        <image name=\"LuLuText\" width=\"1268\" height=\"385\"/>\n    </resources>\n</document>\n"
  },
  {
    "path": "LuLu/App/Base.lproj/StatusBarPopover.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"24128\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"24128\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"StatusBarPopoverController\">\n            <connections>\n                <outlet property=\"label\" destination=\"16\" id=\"U2f-iF-qP9\"/>\n                <outlet property=\"view\" destination=\"1\" id=\"2\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <customView id=\"1\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"320\" height=\"88\"/>\n            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" flexibleMinY=\"YES\" heightSizable=\"YES\"/>\n            <subviews>\n                <imageView horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"14\">\n                    <rect key=\"frame\" x=\"20\" y=\"20\" width=\"48\" height=\"48\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <imageCell key=\"cell\" refusesFirstResponder=\"YES\" alignment=\"left\" imageScaling=\"proportionallyDown\" image=\"Icon\" id=\"15\"/>\n                </imageView>\n                <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"16\">\n                    <rect key=\"frame\" x=\"78\" y=\"46\" width=\"224\" height=\"20\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"LuLu up &amp; running!\" id=\"17\">\n                        <font key=\"font\" size=\"13\" name=\"HelveticaNeue-Bold\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"21\">\n                    <rect key=\"frame\" x=\"78\" y=\"8\" width=\"224\" height=\"30\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" title=\"Access it from here anytime.\" id=\"22\">\n                        <font key=\"font\" metaFont=\"smallSystem\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <button tag=\"2\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"hL7-ZY-bJK\">\n                    <rect key=\"frame\" x=\"281\" y=\"49\" width=\"32\" height=\"32\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <buttonCell key=\"cell\" type=\"bevel\" title=\"⌃\" bezelStyle=\"rounded\" alignment=\"center\" inset=\"2\" id=\"2jG-uf-4XV\">\n                        <behavior key=\"behavior\" pushIn=\"YES\" changeContents=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <connections>\n                        <action selector=\"closePopover:\" target=\"-2\" id=\"hnx-jW-0Ie\"/>\n                    </connections>\n                </button>\n            </subviews>\n            <point key=\"canvasLocation\" x=\"258\" y=\"142\"/>\n        </customView>\n    </objects>\n    <resources>\n        <image name=\"Icon\" width=\"144\" height=\"144\"/>\n    </resources>\n</document>\n"
  },
  {
    "path": "LuLu/App/Base.lproj/UpdateWindow.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"24128\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"24128\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"InfoWindowController\">\n            <connections>\n                <outlet property=\"actionButton\" destination=\"tDD-5C-L8e\" id=\"VA6-H5-ZZO\"/>\n                <outlet property=\"infoLabel\" destination=\"OSm-xS-Dmd\" id=\"Ffv-9q-5a6\"/>\n                <outlet property=\"window\" destination=\"F0z-JX-Cv5\" id=\"gIp-Ho-8D9\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <window title=\"LuLu Update\" allowsToolTipsWhenApplicationIsInactive=\"NO\" autorecalculatesKeyViewLoop=\"NO\" releasedWhenClosed=\"NO\" animationBehavior=\"default\" id=\"F0z-JX-Cv5\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\" closable=\"YES\" texturedBackground=\"YES\"/>\n            <rect key=\"contentRect\" x=\"196\" y=\"240\" width=\"422\" height=\"156\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"1280\" height=\"769\"/>\n            <view key=\"contentView\" id=\"se5-gp-TjO\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"422\" height=\"156\"/>\n                <autoresizingMask key=\"autoresizingMask\"/>\n                <subviews>\n                    <imageView horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"lEv-Wj-6S5\">\n                        <rect key=\"frame\" x=\"10\" y=\"25\" width=\"110\" height=\"106\"/>\n                        <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                        <imageCell key=\"cell\" refusesFirstResponder=\"YES\" alignment=\"left\" imageScaling=\"proportionallyDown\" image=\"Icon\" id=\"xKf-GK-m0k\"/>\n                    </imageView>\n                    <imageView horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Eaf-yA-bbe\">\n                        <rect key=\"frame\" x=\"142\" y=\"79\" width=\"115\" height=\"50\"/>\n                        <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                        <imageCell key=\"cell\" refusesFirstResponder=\"YES\" alignment=\"left\" imageScaling=\"proportionallyDown\" image=\"LuLuText\" id=\"Ws8-bD-j2R\"/>\n                    </imageView>\n                    <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" allowsCharacterPickerTouchBarItem=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"OSm-xS-Dmd\">\n                        <rect key=\"frame\" x=\"142\" y=\"51\" width=\"262\" height=\"30\"/>\n                        <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                        <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" id=\"bBK-v0-ypq\">\n                            <font key=\"font\" size=\"12\" name=\"Menlo-Regular\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <button wantsLayer=\"YES\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"tDD-5C-L8e\">\n                        <rect key=\"frame\" x=\"260\" y=\"13\" width=\"150\" height=\"32\"/>\n                        <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Update\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"nMV-1f-RyK\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" size=\"13\" name=\"Menlo-Regular\"/>\n                        </buttonCell>\n                        <connections>\n                            <action selector=\"buttonHandler:\" target=\"-2\" id=\"tap-If-b45\"/>\n                        </connections>\n                    </button>\n                </subviews>\n            </view>\n            <connections>\n                <outlet property=\"delegate\" destination=\"-2\" id=\"0bl-1N-AYu\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"318\" y=\"263\"/>\n        </window>\n    </objects>\n    <resources>\n        <image name=\"Icon\" width=\"144\" height=\"144\"/>\n        <image name=\"LuLuText\" width=\"1268\" height=\"385\"/>\n    </resources>\n</document>\n"
  },
  {
    "path": "LuLu/App/Base.lproj/Welcome.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"24128\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"24128\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"WelcomeWindowController\">\n            <connections>\n                <outlet property=\"allowApple\" destination=\"b0q-yl-6sv\" id=\"Wjt-Cb-bfM\"/>\n                <outlet property=\"allowDNS\" destination=\"TKV-2M-L24\" id=\"cZl-yn-ymP\"/>\n                <outlet property=\"allowExtActivityIndicator\" destination=\"rJu-8L-JZP\" id=\"5BQ-gP-dc5\"/>\n                <outlet property=\"allowExtMessage\" destination=\"osh-aW-f6g\" id=\"HHi-df-l3Y\"/>\n                <outlet property=\"allowExtensionView\" destination=\"J4K-Wf-OVI\" id=\"NQa-Kx-45w\"/>\n                <outlet property=\"allowInstalled\" destination=\"LHE-lc-cEL\" id=\"ACY-m8-aoi\"/>\n                <outlet property=\"approveExt\" destination=\"VC1-he-DXG\" id=\"r4S-x7-6nr\"/>\n                <outlet property=\"approveExtMessage\" destination=\"zTC-iG-aS4\" id=\"nF6-x8-6sl\"/>\n                <outlet property=\"configureView\" destination=\"kOW-Us-kgD\" id=\"zi8-DA-DXs\"/>\n                <outlet property=\"supportView\" destination=\"2qR-UH-6qk\" id=\"0Pe-jK-kYJ\"/>\n                <outlet property=\"welcomeView\" destination=\"97j-sp-rBE\" id=\"1Cx-EF-YqK\"/>\n                <outlet property=\"window\" destination=\"F0z-JX-Cv5\" id=\"gIp-Ho-8D9\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <window title=\"LuLu\" allowsToolTipsWhenApplicationIsInactive=\"NO\" autorecalculatesKeyViewLoop=\"NO\" releasedWhenClosed=\"NO\" animationBehavior=\"default\" id=\"F0z-JX-Cv5\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\"/>\n            <rect key=\"contentRect\" x=\"196\" y=\"240\" width=\"700\" height=\"350\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"1280\" height=\"770\"/>\n            <value key=\"minSize\" type=\"size\" width=\"700\" height=\"350\"/>\n            <value key=\"maxSize\" type=\"size\" width=\"700\" height=\"350\"/>\n            <view key=\"contentView\" wantsLayer=\"YES\" id=\"se5-gp-TjO\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"700\" height=\"350\"/>\n                <autoresizingMask key=\"autoresizingMask\"/>\n            </view>\n            <connections>\n                <outlet property=\"delegate\" destination=\"-2\" id=\"0bl-1N-AYu\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"140\" y=\"147\"/>\n        </window>\n        <customView id=\"97j-sp-rBE\" userLabel=\"Welcome\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"700\" height=\"350\"/>\n            <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n            <subviews>\n                <box fixedFrame=\"YES\" boxType=\"custom\" borderType=\"none\" titlePosition=\"noTitle\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"JYh-c0-q0Z\">\n                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"700\" height=\"48\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <view key=\"contentView\" id=\"g7q-fa-eZx\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"700\" height=\"48\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                    </view>\n                    <color key=\"fillColor\" red=\"0.57793885469999995\" green=\"0.75859862570000003\" blue=\"0.2368842065\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                </box>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" fixedFrame=\"YES\" preferredMaxLayoutWidth=\"660\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"NEo-Sr-1a0\">\n                    <rect key=\"frame\" x=\"149\" y=\"274\" width=\"338\" height=\"54\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" alignment=\"left\" title=\"Welcome to\" id=\"Qyh-uK-Afv\">\n                        <font key=\"font\" size=\"32\" name=\"AvenirNextCondensed-Regular\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <button tag=\"1\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"xee-73-1JR\">\n                    <rect key=\"frame\" x=\"605\" y=\"6\" width=\"81\" height=\"32\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <buttonCell key=\"cell\" type=\"push\" title=\"Next\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"YXa-F3-XSG\">\n                        <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <connections>\n                        <action selector=\"buttonHandler:\" target=\"-2\" id=\"fII-IA-Yqo\"/>\n                    </connections>\n                </button>\n                <imageView horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"rNc-Xa-Jqh\">\n                    <rect key=\"frame\" x=\"151\" y=\"201\" width=\"238\" height=\"90\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <imageCell key=\"cell\" refusesFirstResponder=\"YES\" alignment=\"left\" imageScaling=\"proportionallyUpOrDown\" image=\"LuLuText\" id=\"zfH-MI-2vJ\"/>\n                </imageView>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" fixedFrame=\"YES\" preferredMaxLayoutWidth=\"660\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"rIh-lu-sTu\">\n                    <rect key=\"frame\" x=\"34\" y=\"132\" width=\"648\" height=\"64\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" alignment=\"center\" title=\"LuLu is a free open-source firewall for macOS.\" id=\"pMo-Yj-XKY\">\n                        <font key=\"font\" size=\"23\" name=\"AvenirNextCondensed-Regular\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <imageView horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"14w-0v-UJ5\">\n                    <rect key=\"frame\" x=\"15\" y=\"202\" width=\"128\" height=\"128\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <imageCell key=\"cell\" refusesFirstResponder=\"YES\" alignment=\"left\" imageScaling=\"proportionallyDown\" image=\"Icon\" id=\"vEL-Yw-xip\"/>\n                </imageView>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" fixedFrame=\"YES\" preferredMaxLayoutWidth=\"660\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"cpq-67-lQt\">\n                    <rect key=\"frame\" x=\"34\" y=\"51\" width=\"647\" height=\"73\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" alignment=\"center\" id=\"eic-lg-Ln7\">\n                        <font key=\"font\" size=\"17\" name=\"AvenirNextCondensed-Regular\"/>\n                        <string key=\"title\">It monitors network activity and alerts you when a program first tries to initiate an outgoing connection, allowing you to permit or deny it.</string>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n            </subviews>\n            <point key=\"canvasLocation\" x=\"-173\" y=\"876\"/>\n        </customView>\n        <customView id=\"J4K-Wf-OVI\" userLabel=\"Allow Ext\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"1018\" height=\"797\"/>\n            <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n            <subviews>\n                <box fixedFrame=\"YES\" boxType=\"custom\" borderType=\"none\" titlePosition=\"noTitle\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"SbF-ut-SRx\">\n                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"1018\" height=\"48\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <view key=\"contentView\" id=\"wvD-es-q1o\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"1018\" height=\"48\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <textField hidden=\"YES\" focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"osh-aW-f6g\">\n                                <rect key=\"frame\" x=\"303\" y=\"15\" width=\"624\" height=\"18\"/>\n                                <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                                <textFieldCell key=\"cell\" lineBreakMode=\"clipping\" title=\"Waiting for System Extension Approval\" id=\"VIe-9o-Kc7\">\n                                    <font key=\"font\" size=\"15\" name=\"Menlo-Regular\"/>\n                                    <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                            <progressIndicator hidden=\"YES\" wantsLayer=\"YES\" fixedFrame=\"YES\" maxValue=\"100\" displayedWhenStopped=\"NO\" indeterminate=\"YES\" style=\"spinning\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"rJu-8L-JZP\">\n                                <rect key=\"frame\" x=\"265\" y=\"8\" width=\"32\" height=\"32\"/>\n                                <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                            </progressIndicator>\n                        </subviews>\n                    </view>\n                    <color key=\"fillColor\" red=\"0.57793885469999995\" green=\"0.75859862570000003\" blue=\"0.2368842065\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                </box>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" fixedFrame=\"YES\" preferredMaxLayoutWidth=\"660\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"bh2-5d-3yL\">\n                    <rect key=\"frame\" x=\"18\" y=\"742\" width=\"664\" height=\"54\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" alignment=\"left\" title=\"First,  allow the LuLu Network Extension:\" id=\"Cwe-NI-HiJ\">\n                        <font key=\"font\" size=\"32\" name=\"AvenirNextCondensed-Regular\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <imageView horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"JJh-FW-P86\">\n                    <rect key=\"frame\" x=\"71\" y=\"467\" width=\"261\" height=\"261\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <imageCell key=\"cell\" refusesFirstResponder=\"YES\" alignment=\"left\" imageScaling=\"proportionallyDown\" image=\"InstallBlocked\" id=\"F3Z-Lx-5ln\"/>\n                </imageView>\n                <imageView horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"0hZ-ai-V42\">\n                    <rect key=\"frame\" x=\"570\" y=\"122\" width=\"261\" height=\"261\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <imageCell key=\"cell\" refusesFirstResponder=\"YES\" alignment=\"left\" imageScaling=\"proportionallyDown\" image=\"InstallAllow\" id=\"Y8g-u9-oUy\"/>\n                </imageView>\n                <imageView horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"VC1-he-DXG\">\n                    <rect key=\"frame\" x=\"492\" y=\"488\" width=\"404\" height=\"219\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <imageCell key=\"cell\" refusesFirstResponder=\"YES\" alignment=\"left\" imageScaling=\"proportionallyDown\" image=\"InstallApprove\" id=\"M64-G3-LAa\"/>\n                </imageView>\n                <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"sZy-xy-LWr\">\n                    <rect key=\"frame\" x=\"57\" y=\"402\" width=\"309\" height=\"48\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" alignment=\"center\" title=\"1. In the &quot;System Extension Blocked&quot; alert, click: &quot;Open System Settings&quot;\" id=\"C1V-iy-oEo\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"zTC-iG-aS4\">\n                    <rect key=\"frame\" x=\"478\" y=\"402\" width=\"453\" height=\"48\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" alignment=\"center\" title=\"...\" id=\"EOD-Hh-8e5\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"EE9-oh-Y1l\">\n                    <rect key=\"frame\" x=\"83\" y=\"72\" width=\"236\" height=\"32\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" lineBreakMode=\"clipping\" alignment=\"center\" title=\"3. Authenticate\" id=\"ZZK-2G-iIB\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <imageView horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"mxD-LX-0aN\">\n                    <rect key=\"frame\" x=\"71\" y=\"122\" width=\"261\" height=\"261\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <imageCell key=\"cell\" refusesFirstResponder=\"YES\" alignment=\"left\" imageScaling=\"proportionallyDown\" image=\"InstallAuth\" id=\"7KJ-Vr-FCS\"/>\n                </imageView>\n                <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"dQ7-Ff-Lr3\">\n                    <rect key=\"frame\" x=\"534\" y=\"72\" width=\"341\" height=\"32\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" alignment=\"center\" title=\"4. In the &quot;Filter Network Content&quot; alert, click: &quot;Allow&quot;\" id=\"qYE-G3-j1K\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" fixedFrame=\"YES\" preferredMaxLayoutWidth=\"445\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"BO1-A5-n37\">\n                    <rect key=\"frame\" x=\"18\" y=\"741\" width=\"597\" height=\"15\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" alignment=\"left\" title=\"Note: steps may vary by macOS version\" id=\"8KH-RD-y9L\">\n                        <font key=\"font\" size=\"12\" name=\"Menlo-Regular\"/>\n                        <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n            </subviews>\n            <point key=\"canvasLocation\" x=\"-343\" y=\"1566.5\"/>\n        </customView>\n        <customView id=\"kOW-Us-kgD\" userLabel=\"Configure\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"700\" height=\"350\"/>\n            <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n            <subviews>\n                <box fixedFrame=\"YES\" boxType=\"custom\" borderType=\"none\" titlePosition=\"noTitle\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"f2W-Nn-YWU\">\n                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"700\" height=\"48\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <view key=\"contentView\" id=\"jcK-yh-GlV\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"700\" height=\"48\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <button tag=\"3\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Syw-cO-leg\">\n                                <rect key=\"frame\" x=\"605\" y=\"6\" width=\"81\" height=\"32\"/>\n                                <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                                <buttonCell key=\"cell\" type=\"push\" title=\"Next\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"xbU-XH-hYT\">\n                                    <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                </buttonCell>\n                                <connections>\n                                    <action selector=\"buttonHandler:\" target=\"-2\" id=\"qKL-mL-agM\"/>\n                                </connections>\n                            </button>\n                        </subviews>\n                    </view>\n                    <color key=\"fillColor\" red=\"0.57793885469999995\" green=\"0.75859862570000003\" blue=\"0.2368842065\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                </box>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" fixedFrame=\"YES\" preferredMaxLayoutWidth=\"660\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ikd-wz-01Q\">\n                    <rect key=\"frame\" x=\"31\" y=\"276\" width=\"664\" height=\"54\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" alignment=\"left\" title=\"Now, let's configure LuLu:\" id=\"XHD-XH-wR0\">\n                        <font key=\"font\" size=\"32\" name=\"AvenirNextCondensed-Regular\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <button verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"b0q-yl-6sv\">\n                    <rect key=\"frame\" x=\"177\" y=\"226\" width=\"22\" height=\"44\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <buttonCell key=\"cell\" type=\"check\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"6UN-fn-MkZ\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" size=\"18\" name=\"Menlo-Bold\"/>\n                    </buttonCell>\n                </button>\n                <button verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"LHE-lc-cEL\">\n                    <rect key=\"frame\" x=\"177\" y=\"154\" width=\"22\" height=\"44\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <buttonCell key=\"cell\" type=\"check\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"aZp-4P-816\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\" size=\"20\"/>\n                    </buttonCell>\n                </button>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" fixedFrame=\"YES\" preferredMaxLayoutWidth=\"445\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"AhJ-ov-jbx\">\n                    <rect key=\"frame\" x=\"175\" y=\"189\" width=\"503\" height=\"45\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" title=\"Outgoing connections from Apple-signed programs will be allowed.\" id=\"r1b-Nl-Ii7\">\n                        <font key=\"font\" size=\"12\" name=\"Menlo-Regular\"/>\n                        <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" fixedFrame=\"YES\" preferredMaxLayoutWidth=\"445\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"KHZ-VJ-JkQ\">\n                    <rect key=\"frame\" x=\"177\" y=\"116\" width=\"505\" height=\"45\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" title=\"Outgoing connections from currently installed 3rd-party programs will be allowed.\" id=\"3aO-AI-YtY\">\n                        <font key=\"font\" size=\"12\" name=\"Menlo-Regular\"/>\n                        <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Udh-qU-3t3\">\n                    <rect key=\"frame\" x=\"200\" y=\"231\" width=\"310\" height=\"28\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\" Allow Apple Programs\" id=\"zo1-a0-tPg\">\n                        <font key=\"font\" size=\"17\" name=\"Menlo-Bold\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Gf8-do-3hb\">\n                    <rect key=\"frame\" x=\"200\" y=\"157\" width=\"399\" height=\"28\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\" Allow Already Installed Programs\" id=\"ymJ-tB-qiA\">\n                        <font key=\"font\" size=\"17\" name=\"Menlo-Bold\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <button verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"TKV-2M-L24\">\n                    <rect key=\"frame\" x=\"179\" y=\"82\" width=\"22\" height=\"44\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <buttonCell key=\"cell\" type=\"check\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"BDy-82-lOp\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\" size=\"20\"/>\n                    </buttonCell>\n                </button>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" fixedFrame=\"YES\" preferredMaxLayoutWidth=\"445\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"yI4-k1-boN\">\n                    <rect key=\"frame\" x=\"179\" y=\"45\" width=\"503\" height=\"45\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" title=\"All outgoing UDP traffic on port 53 will be allowed.\" id=\"sAE-Mf-3fz\">\n                        <font key=\"font\" size=\"12\" name=\"Menlo-Regular\"/>\n                        <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"bLF-86-77M\">\n                    <rect key=\"frame\" x=\"202\" y=\"85\" width=\"399\" height=\"28\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\" Allow DNS Traffic\" id=\"SWc-iv-oN4\">\n                        <font key=\"font\" size=\"17\" name=\"Menlo-Bold\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <imageView horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Zct-RU-d1Y\">\n                    <rect key=\"frame\" x=\"26\" y=\"111\" width=\"128\" height=\"128\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <imageCell key=\"cell\" refusesFirstResponder=\"YES\" alignment=\"left\" imageScaling=\"proportionallyDown\" image=\"Icon\" id=\"PwK-g9-sQH\"/>\n                </imageView>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" fixedFrame=\"YES\" preferredMaxLayoutWidth=\"445\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Pgn-jf-IeQ\">\n                    <rect key=\"frame\" x=\"31\" y=\"273\" width=\"597\" height=\"15\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" alignment=\"left\" title=\"These can be changed later, via LuLu's Settings.\" id=\"NCu-fH-K04\">\n                        <font key=\"font\" size=\"12\" name=\"Menlo-Regular\"/>\n                        <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n            </subviews>\n            <point key=\"canvasLocation\" x=\"616\" y=\"894\"/>\n        </customView>\n        <customView id=\"2qR-UH-6qk\" userLabel=\"Support\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"812\" height=\"454\"/>\n            <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n            <subviews>\n                <imageView horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"0L0-vQ-k5x\">\n                    <rect key=\"frame\" x=\"23\" y=\"245\" width=\"128\" height=\"128\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <imageCell key=\"cell\" refusesFirstResponder=\"YES\" alignment=\"left\" imageScaling=\"proportionallyDown\" image=\"Heart\" id=\"NdE-ks-tao\"/>\n                </imageView>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" fixedFrame=\"YES\" preferredMaxLayoutWidth=\"660\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"NuI-gL-I9N\">\n                    <rect key=\"frame\" x=\"153\" y=\"257\" width=\"636\" height=\"110\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" alignment=\"center\" title=\"It's free, open-source, and written by a single (Mac-loving) coder!\" id=\"Uzd-7P-dzG\">\n                        <font key=\"font\" size=\"40\" name=\"AvenirNextCondensed-Regular\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <box fixedFrame=\"YES\" boxType=\"custom\" borderType=\"none\" titlePosition=\"noTitle\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"3oj-Go-OSg\">\n                    <rect key=\"frame\" x=\"0.0\" y=\"1\" width=\"812\" height=\"48\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <view key=\"contentView\" id=\"kck-xf-IsF\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"812\" height=\"48\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <button tag=\"4\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Egj-dP-0oz\">\n                                <rect key=\"frame\" x=\"14\" y=\"6\" width=\"81\" height=\"32\"/>\n                                <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                                <buttonCell key=\"cell\" type=\"push\" title=\"No\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"QA3-Ww-PeC\">\n                                    <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                </buttonCell>\n                                <connections>\n                                    <action selector=\"buttonHandler:\" target=\"-2\" id=\"wuO-3U-ypy\"/>\n                                </connections>\n                            </button>\n                            <button tag=\"5\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Fw5-9c-Tyj\">\n                                <rect key=\"frame\" x=\"718\" y=\"7\" width=\"81\" height=\"32\"/>\n                                <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                                <buttonCell key=\"cell\" type=\"push\" title=\"Yes!\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"Re5-aD-QVR\">\n                                    <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                </buttonCell>\n                                <connections>\n                                    <action selector=\"buttonHandler:\" target=\"-2\" id=\"gWO-uu-4KV\"/>\n                                </connections>\n                            </button>\n                        </subviews>\n                    </view>\n                    <color key=\"fillColor\" red=\"0.57793885469999995\" green=\"0.75859862570000003\" blue=\"0.2368842065\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                </box>\n                <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" alphaValue=\"0.59999999999999998\" id=\"SzT-r7-Ma4\">\n                    <rect key=\"frame\" x=\"290\" y=\"137\" width=\"233\" height=\"29\"/>\n                    <autoresizingMask key=\"autoresizingMask\"/>\n                    <textFieldCell key=\"cell\" lineBreakMode=\"clipping\" alignment=\"center\" title=\"Mahalo to the &quot;Friends Objective-See&quot;\" id=\"7pD-BH-c8i\">\n                        <font key=\"font\" size=\"15\" name=\"AvenirNextCondensed-Regular\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <imageView horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" alphaValue=\"0.90000000000000002\" id=\"AM3-9J-hwR\">\n                    <rect key=\"frame\" x=\"258\" y=\"59\" width=\"138\" height=\"31\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <imageCell key=\"cell\" refusesFirstResponder=\"YES\" alignment=\"left\" imageScaling=\"proportionallyDown\" image=\"FriendsMacPaw\" id=\"Ylq-Y7-0yI\"/>\n                </imageView>\n                <imageView horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" alphaValue=\"0.80000000000000004\" id=\"mxQ-16-QkH\">\n                    <rect key=\"frame\" x=\"573\" y=\"57\" width=\"142\" height=\"31\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <imageCell key=\"cell\" refusesFirstResponder=\"YES\" alignment=\"left\" imageScaling=\"proportionallyDown\" image=\"FriendsHuntress\" id=\"5gc-uV-gX6\"/>\n                </imageView>\n                <imageView horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" alphaValue=\"0.80000000000000004\" id=\"KQq-D5-uls\">\n                    <rect key=\"frame\" x=\"100\" y=\"57\" width=\"142\" height=\"31\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <imageCell key=\"cell\" refusesFirstResponder=\"YES\" alignment=\"left\" animates=\"YES\" imageScaling=\"proportionallyDown\" image=\"FriendsMalwarebytes\" id=\"0Du-KM-jmM\"/>\n                </imageView>\n                <imageView horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" alphaValue=\"0.80000000000000004\" id=\"2M2-4t-B3w\">\n                    <rect key=\"frame\" x=\"724\" y=\"61\" width=\"73\" height=\"25\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <imageCell key=\"cell\" refusesFirstResponder=\"YES\" alignment=\"left\" imageScaling=\"proportionallyDown\" image=\"FriendsiVerify\" id=\"Qy2-wU-bbf\"/>\n                </imageView>\n                <imageView horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" alphaValue=\"0.80000000000000004\" id=\"7sb-Zs-q5d\">\n                    <rect key=\"frame\" x=\"234\" y=\"94\" width=\"102\" height=\"37\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <imageCell key=\"cell\" refusesFirstResponder=\"YES\" alignment=\"left\" imageScaling=\"proportionallyDown\" image=\"FriendsKandji\" id=\"W0a-k0-8a1\"/>\n                </imageView>\n                <imageView horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" alphaValue=\"0.90000000000000002\" id=\"CsL-Yj-dhy\">\n                    <rect key=\"frame\" x=\"362\" y=\"105\" width=\"89\" height=\"31\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <imageCell key=\"cell\" refusesFirstResponder=\"YES\" alignment=\"left\" animates=\"YES\" imageScaling=\"proportionallyDown\" image=\"FriendsFleet\" id=\"jTn-RV-2Tp\"/>\n                </imageView>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" fixedFrame=\"YES\" preferredMaxLayoutWidth=\"660\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"JBN-MO-km3\">\n                    <rect key=\"frame\" x=\"38\" y=\"380\" width=\"664\" height=\"54\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" alignment=\"left\" title=\"Support LuLu?\" id=\"qNj-Zh-8FW\">\n                        <font key=\"font\" size=\"40\" name=\"AvenirNextCondensed-Regular\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" fixedFrame=\"YES\" preferredMaxLayoutWidth=\"660\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"NeU-Pi-VDr\">\n                    <rect key=\"frame\" x=\"290\" y=\"192\" width=\"499\" height=\"57\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Show some love? \" id=\"XBE-gW-YkK\">\n                        <font key=\"font\" size=\"40\" name=\"AvenirNextCondensed-Regular\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <imageView horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" alphaValue=\"0.90000000000000002\" id=\"a5u-a9-9Hv\">\n                    <rect key=\"frame\" x=\"13\" y=\"61\" width=\"77\" height=\"23\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <imageCell key=\"cell\" refusesFirstResponder=\"YES\" alignment=\"left\" imageScaling=\"proportionallyDown\" image=\"FriendsJamf\" id=\"2Ll-Bq-g75\"/>\n                </imageView>\n                <imageView horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" alphaValue=\"0.80000000000000004\" id=\"wYW-XY-DPT\">\n                    <rect key=\"frame\" x=\"416\" y=\"54\" width=\"148\" height=\"36\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <imageCell key=\"cell\" refusesFirstResponder=\"YES\" alignment=\"left\" animates=\"YES\" imageScaling=\"proportionallyDown\" image=\"FriendsSophos\" id=\"ZqJ-o4-Joj\"/>\n                </imageView>\n                <imageView horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" alphaValue=\"0.90000000000000002\" id=\"fcd-Wp-myp\">\n                    <rect key=\"frame\" x=\"476\" y=\"100\" width=\"126\" height=\"29\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <imageCell key=\"cell\" refusesFirstResponder=\"YES\" alignment=\"left\" imageScaling=\"proportionallyDown\" image=\"FriendsPANW\" id=\"Dio-uY-kZm\"/>\n                </imageView>\n            </subviews>\n            <point key=\"canvasLocation\" x=\"685\" y=\"1355\"/>\n        </customView>\n    </objects>\n    <resources>\n        <image name=\"FriendsFleet\" width=\"236\" height=\"96\"/>\n        <image name=\"FriendsHuntress\" width=\"800\" height=\"198\"/>\n        <image name=\"FriendsJamf\" width=\"162\" height=\"56\"/>\n        <image name=\"FriendsKandji\" width=\"1944\" height=\"494\"/>\n        <image name=\"FriendsMacPaw\" width=\"1541\" height=\"181\"/>\n        <image name=\"FriendsMalwarebytes\" width=\"1888\" height=\"301\"/>\n        <image name=\"FriendsPANW\" width=\"1312\" height=\"240\"/>\n        <image name=\"FriendsSophos\" width=\"1201\" height=\"131\"/>\n        <image name=\"FriendsiVerify\" width=\"736\" height=\"268\"/>\n        <image name=\"Heart\" width=\"256\" height=\"256\"/>\n        <image name=\"Icon\" width=\"144\" height=\"144\"/>\n        <image name=\"InstallAllow\" width=\"520\" height=\"468\"/>\n        <image name=\"InstallApprove\" width=\"894\" height=\"317\"/>\n        <image name=\"InstallAuth\" width=\"521\" height=\"593\"/>\n        <image name=\"InstallBlocked\" width=\"520\" height=\"560\"/>\n        <image name=\"LuLuText\" width=\"1268\" height=\"385\"/>\n    </resources>\n</document>\n"
  },
  {
    "path": "LuLu/App/Configure.h",
    "content": "//\n//  Configure.h\n//  LuLu\n//\n//  Created by Patrick Wardle on 2/6/24.\n//  Copyright © 2024 Objective-See. All rights reserved.\n//\n\n#ifndef Configure_h\n#define Configure_h\n\n@import Foundation;\n\n@interface Configure : NSObject\n\n//quit\n-(void)quit;\n\n//install\n-(BOOL)install;\n\n//upgrade\n-(BOOL)upgrade;\n\n//uninstall\n-(BOOL)uninstall;\n\n@end\n\n#endif /* Configure_h */\n"
  },
  {
    "path": "LuLu/App/Configure.m",
    "content": "//\n//  Configure.m\n//  LuLu\n//\n//  Created by Patrick Wardle on 2/6/24.\n//  Copyright © 2024 Objective-See. All rights reserved.\n//\n\n#import \"consts.h\"\n#import \"utilities.h\"\n\n#import \"Configure.h\"\n#import \"Extension.h\"\n#import \"XPCDaemonClient.h\"\n\n/* GLOBALS */\n\n//log handle\nextern os_log_t logHandle;\n\n//xpc for daemon comms\nextern XPCDaemonClient* xpcDaemonClient;\n\n@implementation Configure\n\n//init\n-(id)init\n{\n    //init\n    if(self = [super init])\n    {\n        //if needed, in extension comms\n        if(nil == xpcDaemonClient)\n        {\n            //init\n            xpcDaemonClient = [[XPCDaemonClient alloc] init];\n        }\n    }\n    \n    return self;\n}\n\n//install\n-(BOOL)install\n{\n    //flag\n    BOOL installed = NO;\n    \n    //error\n    NSError* error = nil;\n    \n    //source\n    NSString* source = nil;\n    \n    //destination\n    NSString* destination = nil;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"function '%s' invoked\", __PRETTY_FUNCTION__);\n    \n    //quit LuLu\n    [self quit];\n    \n    //init source\n    source = NSBundle.mainBundle.bundlePath;\n    \n    //init destination\n    destination = [@\"/Applications\" stringByAppendingPathComponent:APP_NAME];\n    \n    //remove any existing LuLu.app\n    if(YES == [NSFileManager.defaultManager fileExistsAtPath:destination])\n    {\n        //not us?\n        // remove\n        if(YES != [source isEqualToString:destination])\n        {\n            //remove\n            if(YES != [NSFileManager.defaultManager removeItemAtPath:destination error:&error])\n            {\n                //err msg\n                os_log_error(logHandle, \"ERROR: failed to remove %{public}@ (error: %{public}@)\", destination, error);\n                goto bail;\n            }\n        }\n    }\n    \n    //copy self into /Applications\n    if(YES != [NSFileManager.defaultManager copyItemAtPath:source toPath:destination error:&error])\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: failed to move %{public}@ to %{public}@ (error: %{public}@)\", source, destination, error);\n        goto bail;\n    }\n    \n    //dbg msg\n    os_log_debug(logHandle, \"moved self into /Applications and will launch...\");\n    \n    //now launch\n    if(nil == [NSWorkspace.sharedWorkspace launchApplicationAtURL:[NSURL fileURLWithPath:destination] options:0 configuration:@{} error:&error])\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: failed to launch  %{public}@, (error: %{public}@)\", destination, error);\n        goto bail;\n    }\n    \n    //happy\n    installed = YES;\n    \nbail:\n    \n    return installed;\n    \n}\n\n//upgrade\n// same as install\n-(BOOL)upgrade\n{\n    //dbg msg\n    os_log_debug(logHandle, \"function '%s' invoked\", __PRETTY_FUNCTION__);\n    \n    return [self install];\n}\n\n//unistall\n-(BOOL)uninstall\n{\n    //flag\n    BOOL errors = NO;\n    \n    //error\n    NSError* error = nil;\n    \n    //app\n    NSString* app = [@\"/Applications\" stringByAppendingPathComponent:APP_NAME];\n    \n    //dbg msg\n    os_log_debug(logHandle, \"function '%s' invoked\", __PRETTY_FUNCTION__);\n    \n    //tell ext. to uninstall\n    // remove rules, etc, etc\n    if(YES != [xpcDaemonClient uninstall])\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: daemon's XPC uninstall logic\");\n        \n        //set flag\n        errors = YES;\n        \n        //but continue onwards\n    }\n    \n    //first, remove login item\n    toggleLoginItem([NSURL fileURLWithPath:app], ACTION_UNINSTALL_FLAG);\n\n    //quit (other) LuLus, network monitor, extension\n    [self quit];\n    \n    //app found in /Apps?\n    if(YES == [NSFileManager.defaultManager fileExistsAtPath:app])\n    {\n        //remove\n        if(YES != [NSFileManager.defaultManager removeItemAtPath:app error:&error])\n        {\n            //set flag\n            errors = YES;\n            \n            //err msg\n            os_log_error(logHandle, \"ERROR: failed to remove %{public}@ (error: %{public}@)\", app, error);\n            \n            //but continue onwards\n            \n        } \n        //dbg msg\n        else\n        {\n            os_log_debug(logHandle, \"removed %{public}@\", app);\n        }\n    }\n    \n    //dbg msg\n    os_log_debug(logHandle, \"uninstalling completed (with any errors? %d)\", errors);\n    \n    return !errors;\n}\n\n//quit\n// and optionally uninstall\n-(void)quit\n{\n    //extension\n    Extension* extension = nil;\n    \n    //source\n    NSString* source = nil;\n    \n    //copy in /Apps\n    NSString* copy = nil;\n    \n    //running copy\n    NSRunningApplication* runningCopy = nil;\n    \n    //error\n    NSError* error = nil;\n    \n    //wait semaphore\n    dispatch_semaphore_t semaphore = 0;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"function '%s' invoked\", __PRETTY_FUNCTION__);\n    \n    //init extension object\n    extension = [[Extension alloc] init];\n    \n    //init source\n    source = NSBundle.mainBundle.bundlePath;\n    \n    //init copy\n    copy = [@\"/Applications\" stringByAppendingPathComponent:APP_NAME];\n    \n    //end LuLu\n    // besides this running instance\n    for(NSDictionary* lulu in findProcesses(@\"LuLu\"))\n    {\n        //pid\n        NSNumber* pid = 0;\n        \n        //extract pid\n        pid = lulu[KEY_PROCESS_ID];\n        \n        //skip self\n        if(pid.intValue == getpid())\n        {\n            //skip\n            continue;\n        }\n        \n        //dbg msg\n        os_log_debug(logHandle, \"terminating %{public}@\", lulu);\n        \n        //kill\n        kill(pid.intValue, SIGKILL);\n    }\n    \n    //terminate NQ\n    [self terminateNetworkMonitor];\n\n    //need to stop extension?\n    if(YES == [extension isExtensionRunning])\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"extension running, will deactivate...\");\n        \n        //have to be running from /Applications for this to work\n        // so if we're not there, spawn a copy to exectute this logic\n        if(YES != [source isEqualToString:copy])\n        {\n            //dbg msg\n            os_log_debug(logHandle, \"will spawn copy from /Applications\");\n            \n            //any existing?\n            if(YES == [NSFileManager.defaultManager fileExistsAtPath:copy])\n            {\n                //remove\n                if(YES != [NSFileManager.defaultManager removeItemAtPath:copy error:&error])\n                {\n                    //err msg\n                    os_log_error(logHandle, \"ERROR: failed to remove %{public}@ (error: %{public}@)\", copy, error);\n                    goto bail;\n                }\n            }\n            \n            //copy self into /Applications\n            if(YES != [NSFileManager.defaultManager copyItemAtPath:source toPath:copy error:&error])\n            {\n                //err msg\n                os_log_error(logHandle, \"ERROR: failed to move %{public}@ to %{public}@ (error: %{public}@)\", source, copy, error);\n                goto bail;\n            }\n            \n            //dbg msg\n            os_log_debug(logHandle, \"launching copy %{public}@, to deactivate extension\", copy);\n            \n            //launch copy\n            runningCopy = [NSWorkspace.sharedWorkspace launchApplicationAtURL:[NSURL fileURLWithPath:copy] options:0 configuration:[NSDictionary dictionaryWithObject:@[@\"-quit\"] forKey:NSWorkspaceLaunchConfigurationArguments] error:&error];\n            if(nil == runningCopy)\n            {\n                //err msg\n                os_log_error(logHandle, \"ERROR: failed to launch copy, %{public}@, (error: %{public}@)\", copy, error);\n                goto bail;\n            }\n            \n            //wait till copy exits\n            while(YES != runningCopy.isTerminated)\n            {\n                [NSThread sleepForTimeInterval:0.1];\n            }\n            \n            //dbg msg\n            os_log_debug(logHandle, \"copy terminated, will delete\");\n            \n            //delete copy\n            if(YES != [NSFileManager.defaultManager removeItemAtPath:copy error:&error])\n            {\n                //err msg\n                os_log_error(logHandle, \"ERROR: failed to remove %{public}@ (error: %{public}@)\", copy, error);\n                goto bail;\n                \n            } \n            \n            //dbg msg\n            os_log_debug(logHandle, \"removed copy %{public}@\", copy);\n        }\n        \n        //(now) running from /Apps\n        // go ahead and remove extension\n        else\n        {\n            //init wait semaphore\n            semaphore = dispatch_semaphore_create(0);\n            \n            //kick off extension activation request\n            [extension toggleExtension:ACTION_DEACTIVATE reply:^(NSError* error)\n            {\n                //toggled ok?\n                if(!error)\n                {\n                    //dbg msg\n                    os_log_debug(logHandle, \"extension deactivated\");\n                }\n                //failed?\n                else\n                {\n                    //err msg\n                    os_log_error(logHandle, \"ERROR: failed to deactivate extension\");\n                }\n                \n                //signal semaphore\n                dispatch_semaphore_signal(semaphore);\n            }];\n                \n            //dbg msg\n            os_log_debug(logHandle, \"waiting system extension deactivation...\");\n            \n            //wait for extension semaphore\n            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);\n            \n            //dbg msg\n            os_log_debug(logHandle, \"extension event triggered\");\n            \n        }\n    }\n    \nbail:\n    \n    return;\n}\n\n//terminate network monitor\n// unless its the non-LuLu version\n-(void)terminateNetworkMonitor\n{\n    //find match\n    // will check if LuLu's, then will terminate\n    for(NSRunningApplication* networkMonitor in [NSRunningApplication runningApplicationsWithBundleIdentifier:@\"com.objective-see.Netiquette\"])\n    {\n        //non LuLu instance?\n        if(YES != [networkMonitor.bundleURL.path hasPrefix:NSBundle.mainBundle.resourcePath]) continue;\n        \n        //dbg msg\n        os_log_debug(logHandle, \"terminating network monitor: %{public}@\", networkMonitor);\n        \n        //terminate\n        [networkMonitor terminate];\n    }\n    \n    return;\n}\n\n@end\n\n"
  },
  {
    "path": "LuLu/App/Extension.h",
    "content": "//\n//  Extension.h\n//  LuLu\n//\n//  Created by Patrick Wardle on 9/11/20.\n//  Copyright (c) 2020 Objective-See. All rights reserved.\n//\n\n@import OSLog;\n@import Foundation;\n@import NetworkExtension;\n@import SystemExtensions;\n\ntypedef void(^replyBlockType)(NSError*);\n\n@interface Extension : NSObject <OSSystemExtensionRequestDelegate>\n\n/* PROPERTIES */\n\n//reply\n@property(nonatomic, copy)replyBlockType replyBlock;\n\n\n/* METHODS */\n\n//submit request to toggle extension\n-(void)toggleExtension:(NSUInteger)action reply:(replyBlockType)reply;\n\n//check if extension is running\n-(BOOL)isExtensionRunning;\n\n//activate/deactive network extension\n-(BOOL)toggleNetworkExtension:(NSUInteger)action;\n\n//get network extension's status\n-(BOOL)isNetworkExtensionEnabled;\n\n@end\n\n"
  },
  {
    "path": "LuLu/App/Extension.m",
    "content": "//\n//  Extension.m\n//  LuLu\n//\n//  Created by Patrick Wardle on 9/11/20.\n//  Copyright (c) 2020 Objective-See. All rights reserved.\n//\n\n#import \"consts.h\"\n#import \"Extension.h\"\n#import \"utilities.h\"\n#import \"AppDelegate.h\"\n\n/* GLOBALS */\n\n//log handle\nextern os_log_t logHandle;\n\n@implementation Extension\n\n//submit request to toggle system extension\n-(void)toggleExtension:(NSUInteger)action reply:(replyBlockType)reply\n{\n    //request\n    OSSystemExtensionRequest* request = nil;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"toggling extension (action: %lu)\", (unsigned long)action);\n    \n    //save reply\n    self.replyBlock = reply;\n        \n    //activation request\n    if(ACTION_ACTIVATE == action)\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"creating activation request\");\n        \n        //init request\n        request = [OSSystemExtensionRequest activationRequestForExtension:EXT_BUNDLE_ID queue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)];\n    }\n    //deactivation request\n    else\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"creating deactivation request\");\n        \n        //init request\n        request = [OSSystemExtensionRequest deactivationRequestForExtension:EXT_BUNDLE_ID queue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)];\n    }\n    \n    //sanity check\n    if(!request) {\n    \n        os_log_error(logHandle, \"ERROR: failed to create request for extension\");\n    \n        //call reply\n        self.replyBlock([NSError errorWithDomain:@BUNDLE_ID code:-1 userInfo:@{NSLocalizedDescriptionKey: @\"Failed to create system extension request\"}]);\n        \n        goto bail;\n    }\n    \n    //set delegate\n    request.delegate = self;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"submitting request\");\n       \n    //submit request\n    [OSSystemExtensionManager.sharedManager submitRequest:request];\n    \n    //dbg msg\n    os_log_debug(logHandle, \"submitting request returned...\");\n    \nbail:\n    \n    return;\n    \n}\n\n//check if extension is running\n-(BOOL)isExtensionRunning\n{\n    return !![findProcesses(EXT_BUNDLE_ID) count];\n}\n\n//get network extension's status\n-(BOOL)isNetworkExtensionEnabled\n{\n    return NEFilterManager.sharedManager.isEnabled;\n}\n\n//activate/deactive network extension\n-(BOOL)toggleNetworkExtension:(NSUInteger)action\n{\n    //flag\n    BOOL toggled = NO;\n    \n    //error\n    __block BOOL wasError = NO;\n    \n    //config\n    NEFilterProviderConfiguration* config = nil;\n    \n    //wait semaphore\n    dispatch_semaphore_t semaphore = 0;\n    \n    //init wait semaphore\n    semaphore = dispatch_semaphore_create(0);\n    \n    //dbg msg\n    os_log_debug(logHandle, \"toggling network extension: %lu\", (unsigned long)action);\n    \n    //load prefs\n    [NEFilterManager.sharedManager loadFromPreferencesWithCompletionHandler:^(NSError * _Nullable error) {\n        \n        //err?\n        if(nil != error)\n        {\n            //set flag\n            wasError = YES;\n            \n            //err msg\n            os_log_error(logHandle, \"ERROR: 'loadFromPreferencesWithCompletionHandler' failed with %{public}@\", error);\n        }\n    \n        //signal semaphore\n        dispatch_semaphore_signal(semaphore);\n        \n    }];\n    \n    //dbg msg\n    os_log_debug(logHandle, \"waiting for network extension configuration...\");\n    \n    //wait for request to complete\n    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);\n      \n    //error?\n    if(YES == wasError) goto bail;\n   \n    //dbg msg\n    os_log_debug(logHandle, \"loaded current filter configuration for the network extension\");\n\n    //activate?\n    // create new config, configure, save\n    if(ACTION_ACTIVATE == action)\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"activating network extension...\");\n        \n        //already enabled\n        // good to go already\n        if(NEFilterManager.sharedManager.enabled == YES) {\n            os_log_debug(logHandle, \"network extension already enabled; skipping save\");\n            \n            //done\n            toggled = YES;\n            goto bail;\n        }\n        \n        \n        //init config\n        config = [[NEFilterProviderConfiguration alloc] init];\n            \n        //don't care about packets\n        config.filterPackets = NO;\n            \n        //filter sockets\n        config.filterSockets = YES;\n        \n        //set config\n        NEFilterManager.sharedManager.providerConfiguration = config;\n        \n        //set flag\n        NEFilterManager.sharedManager.enabled = YES;\n    }\n    \n    //deactivate\n    // just set 'enabled' flag to NO\n    else\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"deactivating network extension...\");\n        \n        //set flag\n        NEFilterManager.sharedManager.enabled = NO;\n    }\n    \n    //save preferences\n    { [NEFilterManager.sharedManager saveToPreferencesWithCompletionHandler:^(NSError * _Nullable error) {\n        \n        //error?\n        if(nil != error)\n        {\n            //set flag\n            wasError = YES;\n            \n            //err msg\n            os_log_error(logHandle, \"ERROR: 'saveToPreferencesWithCompletionHandler' failed with %{public}@\", error);\n        }\n        \n        //signal semaphore\n        dispatch_semaphore_signal(semaphore);\n            \n    }]; }\n    \n    //dbg msg\n    os_log_debug(logHandle, \"waiting for network extension configuration to save...\");\n    \n    //wait for request to complete\n    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);\n    \n    //error?\n    if(YES == wasError) goto bail;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"saved current filter configuration for the network extension\");\n    \n    //happy\n    toggled = YES;\n        \nbail:\n    \n    return toggled;\n}\n\n#pragma mark -\n#pragma mark OSSystemExtensionRequest delegate methods\n\n//replace delegate method\n// always replaces, so return 'OSSystemExtensionReplacementActionReplace'\n-(OSSystemExtensionReplacementAction)request:(nonnull OSSystemExtensionRequest *)request actionForReplacingExtension:(nonnull OSSystemExtensionProperties *)existing withExtension:(nonnull OSSystemExtensionProperties *)ext\n{\n    //dbg msg\n    os_log_debug(logHandle, \"method '%s' invoked with %{public}@, %{public}@ -> %{public}@\", __PRETTY_FUNCTION__, request.identifier, existing.bundleShortVersion, ext.bundleShortVersion);\n    \n    return OSSystemExtensionReplacementActionReplace;\n}\n\n//error delegate method\n-(void)request:(nonnull OSSystemExtensionRequest *)request didFailWithError:(nonnull NSError *)error\n{\n    //err msg\n    os_log_error(logHandle, \"ERROR: method '%s' invoked with %{public}@, %{public}@\", __PRETTY_FUNCTION__, request, error);\n    \n    //invoke reply\n    self.replyBlock(error);\n\n    return;\n}\n\n//finish delegate method\n// install request? now can activate network ext\n// uninstall request? now can complete uninstall\n-(void)request:(nonnull OSSystemExtensionRequest *)request didFinishWithResult:(OSSystemExtensionRequestResult)result {\n    \n    //happy\n    NSError* error = nil;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"method '%s' invoked with %{public}@, %ld\", __PRETTY_FUNCTION__, request, (long)result);\n   \n    //issue/error?\n    if(OSSystemExtensionRequestCompleted != result)\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: result %ld is an unexpected result for system extension request\", (long)result);\n        \n        //set error\n        error = [NSError errorWithDomain:@BUNDLE_ID\n                                            code:result\n                                        userInfo:@{\n                                            NSLocalizedDescriptionKey: [NSString stringWithFormat:@\"System extension request failed with result: %ld\", (long)result],\n                                            NSLocalizedFailureReasonErrorKey: @\"Unexpected result from system extension request\",\n        }];\n    }\n    \n    //reply\n    self.replyBlock(error);\n    \n    return;\n}\n\n//user approval delegate\n// if this isn't the first time launch, will alert user to approve\n-(void)requestNeedsUserApproval:(nonnull OSSystemExtensionRequest *)request {\n    \n    //dbg msg\n    os_log_debug(logHandle, \"method '%s' invoked with %{public}@\", __PRETTY_FUNCTION__, request);\n    \n    //not user launched?\n    // show alert on desktop\n    if(YES != launchedByUser())\n    {\n        //on main thread\n        // check and invoke\n        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{\n            \n            //not first time?\n            // show alert telling user to approve extension\n            if(YES != [((AppDelegate*)[[NSApplication sharedApplication] delegate]) isFirstTime])\n            {\n                //show alert\n                showAlert(NSAlertStyleInformational, NSLocalizedString(@\"LuLu's Network Extension Is Not Running\", @\"LuLu's Network Extension Is Not Running\"), NSLocalizedString(@\"Extensions must be manually approved via System Settings (General > Login Items & Extensions > Network Extensions).\",@\"Extensions must be manually approved via System Settings (General > Login Items & Extensions > Network Extensions).\"), @[NSLocalizedString(@\"OK\", @\"OK\")]);\n            }\n        });\n    }\n    \n    return;\n}\n\n@end\n"
  },
  {
    "path": "LuLu/App/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIconFile</key>\n\t<string></string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>$(MARKETING_VERSION)</string>\n\t<key>CFBundleVersion</key>\n\t<string>$(CURRENT_PROJECT_VERSION)</string>\n\t<key>LSMinimumSystemVersion</key>\n\t<string>$(MACOSX_DEPLOYMENT_TARGET)</string>\n\t<key>LSUIElement</key>\n\t<true/>\n\t<key>NSHumanReadableCopyright</key>\n\t<string>Copyright (c) 2020 Objective-See. All rights reserved.</string>\n\t<key>NSMainNibFile</key>\n\t<string>MainMenu</string>\n\t<key>NSPrincipalClass</key>\n\t<string>NSApplicationKeyEvents</string>\n\t<key>NSSupportsAutomaticTermination</key>\n\t<true/>\n\t<key>NSSupportsSuddenTermination</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "LuLu/App/InfoPlist.xcstrings",
    "content": "{\n  \"sourceLanguage\" : \"en\",\n  \"strings\" : {\n    \"CFBundleName\" : {\n      \"comment\" : \"Bundle name\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"LuLu\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu\"\n          }\n        }\n      }\n    },\n    \"NSHumanReadableCopyright\" : {\n      \"comment\" : \"Copyright (human-readable)\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Copyright (c) 2020 Objective-See. Alle Rechte vorbehalten.\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Copyright (c) 2020 Objective-See. All rights reserved.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Copyright (c) 2020 Objective-See. Todos los derechos reservados.\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Copyright (c) 2020 Objective-See. 모든 권리 보유.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Copyright (c) 2020 Objective-See. Todos os direitos reservados.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Telif hakkı © 2020 Objective-See. Tüm hakları saklıdır.\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"کاپی رائٹ (c) 2020 Objective-See۔ تمام حقوق محفوظ ہیں۔\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"版权所有 (c) 2020 Objective-See. 保留一切权利。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"版權所有 (c) 2020 Objective-See. 保留一切權利。\"\n          }\n        }\n      }\n    }\n  },\n  \"version\" : \"1.0\"\n}"
  },
  {
    "path": "LuLu/App/ItemPathsWindowController.h",
    "content": "//\n//  ItemPathsWindowController.h\n//  LuLu\n//\n//  Created by Patrick Wardle on 9/19/20.\n//  Copyright (c) 2020 Objective-See. All rights reserved.\n//\n\n@import Cocoa;\n@import OSLog;\n\n#import \"Rule.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface ItemPathsWindowController : NSWindowController\n\n//title\n@property (weak) IBOutlet NSTextField* heading;\n\n//item's rules\n@property(nonatomic, retain)NSDictionary* item;\n\n//item paths\n@property (weak) IBOutlet NSTextField* itemPaths;\n\n//close button\n@property (weak) IBOutlet NSButton* closeButton;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "LuLu/App/ItemPathsWindowController.m",
    "content": "//\n//  ItemPathsWindowController.m\n//  LuLu\n//\n//  Created by Patrick Wardle on 9/19/20.\n//  Copyright (c) 2020 Objective-See. All rights reserved.\n//\n\n#import \"consts.h\"\n#import \"signing.h\"\n#import \"utilities.h\"\n#import \"XPCDaemonClient.h\"\n#import \"ItemPathsWindowController.h\"\n\n/* GLOBALS */\n\n//log handle\nextern os_log_t logHandle;\n\n//xpc for daemon comms\nextern XPCDaemonClient* xpcDaemonClient;\n\n@implementation ItemPathsWindowController\n\n@synthesize item;\n\n//generate and show paths\n-(void)windowDidLoad {\n    \n    //rule\n    Rule* rule = nil;\n    \n    //super\n    [super windowDidLoad];\n    \n    //unique paths\n    NSMutableSet* paths = nil;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"method '%s' invoked\", __PRETTY_FUNCTION__);\n    \n    //extract (first) rule\n    rule = [self.item[KEY_RULES] firstObject];\n    \n    //set heading if 'normal' rule\n    if(!rule.isGlobal.boolValue &&\n       !rule.isDirectory.boolValue) {\n        \n        //set heading\n        self.heading.stringValue = [NSString stringWithFormat:NSLocalizedString(@\"Path(s) for %@:\", nil), rule.name];\n    }\n    //reset heading\n    else {\n        self.heading.stringValue = NSLocalizedString(@\"Path(s):\", nil);\n    }\n    \n    //get paths\n    paths = [self getPaths];\n    \n    //each rule's path\n    for(NSString* path in paths)\n    {\n        if(0 == self.itemPaths.stringValue.length)\n        {\n            self.itemPaths.stringValue = [NSString stringWithFormat:@\"▪ %@\", path];\n        }\n        //otherwise\n        // append to existing\n        else\n        {\n            self.itemPaths.stringValue = [NSString stringWithFormat:@\"%@\\r\\n▪ %@\", self.itemPaths.stringValue, path];\n        }\n    }\n\n    //make close button first responder\n    [self.window makeFirstResponder:self.closeButton];\n\n    return;\n}\n\n//get all unique paths for item\n// both from rules, but also from system (via bundle ID)\n-(NSMutableSet*)getPaths\n{\n    //(first) rule\n    Rule* rule = nil;\n    \n    //items\n    NSArray* items = nil;\n    \n    //paths\n    NSMutableSet* paths = nil;\n    \n    //item bundle id\n    NSString* bundleID = nil;\n        \n    //signing info\n    NSMutableDictionary* signingInfo = nil;\n    \n    //init\n    paths = [NSMutableSet set];\n    \n    //extract (first) rule\n    rule = [self.item[KEY_RULES] firstObject];\n    \n    //global rule?\n    if(YES == rule.isGlobal.boolValue)\n    {\n        //set message\n        [paths addObject:NSLocalizedString(@\"Global Rules apply to all paths\", @\"Global Rules apply to all paths\")];\n        \n        //done\n        goto bail;\n    }\n    \n    //directory rule?\n    if(YES == rule.isDirectory.boolValue)\n    {\n        //set message\n        [paths addObject:NSLocalizedString(@\"Directory Rules apply to all items within the directory\", @\"Directory Rules apply to all items within the directory\")];\n        \n        //done\n        goto bail;\n    }\n    \n    //first add rule's path\n    if(nil != rule.path)\n    {\n        //add\n        [paths addObject:rule.path];\n    }\n\n    //add any external paths\n    [paths unionSet:item[KEY_PATHS]];\n    \n    //grab bundle id\n    bundleID = rule.csInfo[KEY_CS_ID];\n    \n    //add other items on system\n    // with same bundle id *and* cs info, as these will match\n    if(nil != bundleID)\n    {\n        //get matching apps\n        items = (__bridge NSArray *)(LSCopyApplicationURLsForBundleIdentifier((__bridge CFStringRef _Nonnull)(bundleID), nil));\n        \n        //get each item's binary\n        for(NSURL* item in items)\n        {\n            //path\n            NSString* path = nil;\n            \n            //attempt to get path via bundle\n            path = getBundleExecutable(item.path);\n            \n            //likely not bundle\n            if(0 == path.length)\n            {\n                path = item.path;\n            }\n            \n            //sanity check\n            if(0 == path.length)\n            {\n                //skip\n                continue;\n            }\n            \n            //extract signing info and check\n            // note: use item's path, to match rule\n            signingInfo = extractSigningInfo(0, item.path, kSecCSDefaultFlags);\n            if(YES != matchesCSInfo(self.item[KEY_CS_INFO], signingInfo))\n            {\n                //dbg msg\n                os_log_debug(logHandle, \"rule's code signing info %{public}@ doesn't match item's %{public}@\", self.item[KEY_CS_INFO], signingInfo);\n                \n                //skip\n                continue;\n            }\n            \n            //add\n            [paths addObject:path];\n        }\n    }\n    \nbail:\n    \n    return paths;\n    \n}\n\n//close\n-(IBAction)closeButtonHandler:(id)sender {\n    \n    //dbg msg\n    os_log_debug(logHandle, \"user clicked: %{public}@\", ((NSButton*)sender).title);\n    \n    //close & return NSModalResponseCancel\n    [self.window.sheetParent endSheet:self.window returnCode:NSModalResponseOK];\n    \n    return;\n}\n\n@end\n"
  },
  {
    "path": "LuLu/App/NSApplicationKeyEvents.h",
    "content": "//\n//  file: NSApplicationKeyEvents.h\n//  project: LuLu\n//  description: adds support for keyboard shortcuts (header)\n//\n//  created by Patrick Wardle\n//  copyright (c) 2020 Objective-See. All rights reserved.\n//\n\n@import Cocoa;\n\n@interface NSApplicationKeyEvents : NSApplication\n\n@end\n"
  },
  {
    "path": "LuLu/App/NSApplicationKeyEvents.m",
    "content": "//\n//  file: NSApplicationKeyEvents.h\n//  project: LuLu\n//  description: adds support for keyboard shortcuts (header)\n//\n//  created by Patrick Wardle\n//  copyright (c) 2020 Objective-See. All rights reserved.\n//\n\n#import \"consts.h\"\n#import \"AppDelegate.h\"\n#import \"NSApplicationKeyEvents.h\"\n\n@implementation NSApplicationKeyEvents\n\n//to enable copy/paste etc even though we don't have an 'Edit' menu\n// details: http://stackoverflow.com/questions/970707/cocoa-keyboard-shortcuts-in-dialog-without-an-edit-menu\n-(void)sendEvent:(NSEvent*)event\n{\n    //only care about key down\n    if(NSEventTypeKeyDown != event.type)\n    {\n        //bail\n        goto bail;\n    }\n        \n    //delete?\n    // in Rules window/table, delete row\n    if( (NSDeleteCharacter == [event.charactersIgnoringModifiers characterAtIndex:0]) &&\n        (YES == [event.window.identifier isEqualToString:@\"Rules\"]) &&\n        (YES == [event.window.firstResponder.className isEqualToString:@\"RulesTable\"]) )\n    {\n        //delete rule\n        [[((AppDelegate*)[[NSApplication sharedApplication] delegate]) rulesWindowController] deleteRule:nil];\n        return;\n    }\n    \n    //otherwise\n    // ...only care about key down + command\n    if(NSEventModifierFlagCommand != (event.modifierFlags & NSEventModifierFlagDeviceIndependentFlagsMask))\n    {\n        //bail\n        goto bail;\n    }\n    \n    //+c (copy)\n    if(YES == [event.charactersIgnoringModifiers isEqualToString:@\"c\"])\n    {\n        //copy\n        if(YES == [self sendAction:@selector(copy:) to:nil from:self])\n        {\n            return;\n        }\n    }\n            \n    //+v (paste)\n    else if ([event.charactersIgnoringModifiers isEqualToString:@\"v\"])\n    {\n        //paste\n        if(YES == [self sendAction:@selector(paste:) to:nil from:self])\n        {\n            return;\n        }\n    }\n            \n    //+x (cut)\n    else if ([event.charactersIgnoringModifiers isEqualToString:@\"x\"])\n    {\n        //cut\n        if(YES == [self sendAction:@selector(cut:) to:nil from:self])\n        {\n            return;\n        }\n    }\n            \n    //+a (select all)\n    else if([event.charactersIgnoringModifiers isEqualToString:@\"a\"])\n    {\n        //select\n        if(YES == [self sendAction:@selector(selectAll:) to:nil from:self])\n        {\n            return;\n        }\n    }\n    \n    //+h (hide window)\n    else if([event.charactersIgnoringModifiers isEqualToString:@\"h\"])\n    {\n        //hide\n        if(YES == [self sendAction:@selector(hide:) to:nil from:self])\n        {\n            return;\n        }\n    }\n    \n    //+m (minimize window)\n    else if([event.charactersIgnoringModifiers isEqualToString:@\"m\"])\n    {\n        //minimize\n        [NSApplication.sharedApplication.keyWindow miniaturize:nil];\n        return;\n    }\n    \n    //+w (close window)\n    // unless its an alert ...need response!\n    else if( ([event.charactersIgnoringModifiers isEqualToString:@\"w\"]) &&\n             (YES != [event.window.identifier isEqualToString:@\"Alert\"]) )\n    {\n        //close\n        [NSApplication.sharedApplication.keyWindow close];\n        return;\n    }\n\n    //+f (find, but only in rules window)\n    else if( ([event.charactersIgnoringModifiers isEqualToString:@\"f\"]) &&\n             (YES == [event.window.identifier isEqualToString:@\"Rules\"]) )\n    {\n        //iterate over all toolbar items\n        // ...find rule search field, and select\n        for(NSToolbarItem* item in NSApplication.sharedApplication.keyWindow.toolbar.items)\n        {\n            //not search field? skip\n            if(RULE_SEARCH_FIELD != item.tag) continue;\n            \n            //and make it first responder\n            [NSApplication.sharedApplication.keyWindow makeFirstResponder:item.view];\n            \n            //done\n            return;\n        }\n    }\n    \n    //+, (show preferences)\n    else if([event.charactersIgnoringModifiers isEqualToString:@\",\"])\n    {\n        //show\n        [((AppDelegate*)[[NSApplication sharedApplication] delegate]) showPreferences:nil];\n        return;\n    }\n    \nbail:\n\n    //super\n    [super sendEvent:event];\n    \n    return;\n}\n\n@end\n"
  },
  {
    "path": "LuLu/App/ParentsWindowController.h",
    "content": "//\n//  file: ParentsWindowController.h\n//  project: lulu (login item)\n//  description: window controller for process heirachy (header)\n//\n//  created by Patrick Wardle\n//  copyright (c) 2017 Objective-See. All rights reserved.\n//\n\n@import Cocoa;\n\n@interface ParentsWindowController : NSViewController <NSOutlineViewDataSource, NSOutlineViewDelegate>\n{\n    \n}\n\n/* PROPERTIES */\n\n//process hierarchy\n@property (nonatomic, retain)NSArray* processHierarchy;\n\n/* METHODS */\n\n@end\n"
  },
  {
    "path": "LuLu/App/ParentsWindowController.m",
    "content": "//\n//  file: ParentsWindowController.m\n//  project: lulu (login item)\n//  description: window controller for process heirachy\n//\n//  created by Patrick Wardle\n//  copyright (c) 2017 Objective-See. All rights reserved.\n//\n\n#import \"consts.h\"\n#import \"ParentsWindowController.h\"\n\n@implementation ParentsWindowController\n\n//automatically invoked\n// return number of children, simply either 1, or 0 (for last item)\n-(NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item\n{\n    //# of kids\n    // defaults to 1\n    NSInteger kidCount = 1;\n    \n    //for last item\n    // no more kids...\n    if( (1 != self.processHierarchy.count) &&\n        ([((NSDictionary*)item)[KEY_INDEX] integerValue] == self.processHierarchy.count-1) )\n    {\n        //no kids\n        kidCount = 0;\n    }\n    \n    return kidCount;\n}\n\n//automatically invoked to determine if item is expandable\n// always the case, except for the last item\n-(BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item\n{\n    //flag\n    // ->defaults to yes\n    BOOL isExpandable = YES;\n    \n    //for last item\n    // no kids, so obv. no expandable\n    if([((NSDictionary*)item)[KEY_INDEX] integerValue] == self.processHierarchy.count-1)\n    {\n        //last one\n        isExpandable = NO;\n    }\n    \n    return isExpandable;\n}\n\n//automatically invoked to get the child item\n-(id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item\n{\n    //item\n    id itemForRow = nil;\n    \n    //item is nil for root\n    // just provide root item\n    if(nil == item)\n    {\n        //first item\n        itemForRow = self.processHierarchy[0];\n    }\n    \n    //other items\n    // return *their* child!\n    else\n    {\n        //child at index\n        itemForRow = self.processHierarchy[[((NSDictionary*)item)[KEY_INDEX] integerValue]+1];\n    }\n    \n    return itemForRow;\n}\n\n//automatically invoked to get the object for the row\n// return items name/pid\n-(id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item\n{\n    //row value\n    NSString* rowValue = nil;\n    \n    //init string for row\n    // process name + pid\n    //  note: if this format changes, also change row width calculation in AlertWindowController!\n    rowValue = [NSString stringWithFormat:NSLocalizedString(@\"%@ (pid: %@)\",@\"%@ (pid: %@)\"), ((NSDictionary*)item)[KEY_PROCESS_NAME], ((NSDictionary*)item)[@\"pid\"]];\n    \n    return rowValue;\n}\n\n@end\n"
  },
  {
    "path": "LuLu/App/PrefsWindowController.h",
    "content": "//\n//  file: PrefsWindowController.h\n//  project: lulu (main app)\n//  description: preferences window controller (header)\n//\n//  created by Patrick Wardle\n//  copyright (c) 2017 Objective-See. All rights reserved.\n//\n\n@import Cocoa;\n@import OSLog;\n\n#import \"XPCDaemonClient.h\"\n#import \"UpdateWindowController.h\"\n\n/* CONSTS */\n\n//rules view\n#define TOOLBAR_RULES 0\n\n//modes view\n#define TOOLBAR_MODES 1\n\n//update view\n#define TOOLBAR_LISTS 2\n\n//profiles view\n#define TOOLBAR_PROFILES 3\n\n//update view\n#define TOOLBAR_UPDATE 4\n\n//to select, need string ID\n#define TOOLBAR_RULES_ID @\"Rules\"\n#define TOOLBAR_PROFILES_ID @\"Profiles\"\n\n@interface PrefsWindowController : NSWindowController <NSWindowDelegate, NSTableViewDelegate, NSTableViewDataSource>\n\n/* PROPERTIES */\n\n//preferences\n@property(nonatomic, retain)NSDictionary* preferences;\n\n//toolbar\n@property (weak) IBOutlet NSToolbar* toolbar;\n\n/* RULES */\n\n//rules prefs view\n@property (weak) IBOutlet NSView* rulesView;\n\n//show rules button\n@property (weak) IBOutlet NSButton* showRulesButton;\n\n/* MODES */\n\n//modes view\n@property (strong) IBOutlet NSView* modesView;\n\n//passive mode action ...allow or block?\n@property (weak) IBOutlet NSPopUpButton* passiveModeAction;\n\n//passive mode rules ...create, or not?\n@property (weak) IBOutlet NSPopUpButton* passiveModeRules;\n\n//(block/allow) lists view\n@property (strong) IBOutlet NSView *listsView;\n\n//allow list\n@property (weak) IBOutlet NSTextField *allowList;\n\n//select allow list button\n@property (weak) IBOutlet NSButton *selectAllowListButton;\n\n//block list\n@property (weak) IBOutlet NSTextField* blockList;\n\n//select block list button\n@property (weak) IBOutlet NSButton* selectBlockListButton;\n\n//profiles table\n@property (weak) IBOutlet NSTableView *profilesTable;\n\n/* PROFILES VIEW */\n\n//profiles view\n@property (strong) IBOutlet NSView* profilesView;\n\n//profiles\n@property(nonatomic, retain)NSMutableArray* profiles;\n\n//selected profile\n@property(nonatomic, retain)NSString* selectedProfile;\n\n//add profile sheet\n@property (strong) IBOutlet NSPanel* addProfileSheet;\n\n//continue/next button\n@property (weak) IBOutlet NSButton* continueProfileButton;\n\n//current view\n@property (strong) NSView* currentProfileSubview;\n\n//profile name label\n@property (weak) IBOutlet NSTextField* profileNameLabel;\n\n//profile name view\n@property (strong) IBOutlet NSView* profileNameView;\n\n//new profile name\n@property(nonatomic, retain)NSString* profileName;\n\n//profile preferences\n@property(nonatomic, retain)NSMutableDictionary* profilePreferences;\n\n//profile views\nenum profileViews\n{\n    profileName = 0,\n    profileRules,\n    profileModes,\n    profileLists,\n    profileUpdates,\n};\n\n/* UPDATE VIEW */\n\n//update view\n@property (weak) IBOutlet NSView* updateView;\n\n//update button\n@property (weak) IBOutlet NSButton* updateButton;\n\n//update indicator (spinner)\n@property (weak) IBOutlet NSProgressIndicator* updateIndicator;\n\n//update label\n@property (weak) IBOutlet NSTextField* updateLabel;\n\n//update window controller\n@property(nonatomic, retain)UpdateWindowController* updateWindowController;\n\n//added view\n@property (nonatomic) BOOL viewWasAdded;\n\n\n/* METHODS */\n\n//toolbar button handler\n-(IBAction)toolbarButtonHandler:(id)sender;\n\n//switch to tab\n-(void)switchTo:(NSString*)itemID;\n\n//button handler for all preference buttons\n-(IBAction)togglePreference:(id)sender;\n\n//reload UI\n-(void)reload;\n\n@end\n"
  },
  {
    "path": "LuLu/App/PrefsWindowController.m",
    "content": "//\n//  file: PrefsWindowController.h\n//  project: lulu (main app)\n//  description: preferences window controller (header)\n//\n//  created by Patrick Wardle\n//  copyright (c) 2017 Objective-See. All rights reserved.\n//\n\n#import \"consts.h\"\n#import \"Update.h\"\n#import \"utilities.h\"\n#import \"AppDelegate.h\"\n#import \"PrefsWindowController.h\"\n#import \"UpdateWindowController.h\"\n\n/* GLOBALS */\n\n//log handle\nextern os_log_t logHandle;\n\n//xpc for daemon comms\nextern XPCDaemonClient* xpcDaemonClient;\n\n@implementation PrefsWindowController\n\n@synthesize toolbar;\n@synthesize modesView;\n@synthesize rulesView;\n@synthesize updateView;\n@synthesize updateWindowController;\n\n//'allow apple' button\n#define BUTTON_ALLOW_APPLE 1\n\n//'allow installed' button\n#define BUTTON_ALLOW_INSTALLED 2\n\n//'allow dns' button\n#define BUTTON_ALLOW_DNS 3\n\n//'allow localhost' button\n#define BUTTON_ALLOW_LOCALHOST 4\n\n//'allow iOS simulator apps' mode button\n#define BUTTON_ALLOW_SIMULATOR 5\n\n//'passive mode' button\n#define BUTTON_PASSIVE_MODE 6\n\n//'block mode' button\n#define BUTTON_BLOCK_MODE 7\n\n//'no-icon mode' button\n#define BUTTON_NO_ICON_MODE 8\n\n//'no-VT mode' button\n#define BUTTON_NO_VT_MODE 9\n\n//'use allow list' button\n#define BUTTON_USE_ALLOW_LIST 10\n\n//'use block list' button\n#define BUTTON_USE_BLOCK_LIST 11\n\n//'update mode' button\n#define BUTTON_NO_UPDATE_MODE 12\n\n//'passive mode' actions\n#define BUTTON_PASSIVE_MODE_ACTION_ALLOW 0\n#define BUTTON_PASSIVE_MODE_ACTION_BLOCK 1\n\n//init 'general' view\n// add it, and make it selected\n-(void)awakeFromNib\n{\n    //set subtitle\n    [self setSubTitle];\n    \n    //get prefs\n    self.preferences = [xpcDaemonClient getPreferences];\n    \n    return;\n}\n\n//set subtitle to current profile\n-(void)setSubTitle\n{\n    //dbg msg\n    os_log_debug(logHandle, \"method '%s' invoked\", __PRETTY_FUNCTION__);\n    \n    //current profile\n    NSString* currentProfile = [xpcDaemonClient getCurrentProfile];\n    \n    //have profile?\n    if(0 != currentProfile.length) {\n        \n        //add subtitle\n        if (@available(macOS 11.0, *)) {\n            self.window.subtitle = [NSString stringWithFormat:NSLocalizedString(@\"Current Profile: %@\",@\"Current Profile: %@\"), currentProfile];\n        }\n    }\n    //set to default\n    else\n    {\n        //set\n        if (@available(macOS 11.0, *)) {\n            self.window.subtitle = NSLocalizedString(@\"Current Profile: Default\",@\"Current Profile: Default\");\n        }\n    }\n    \n    return;\n}\n\n//switch to tab\n-(void)switchTo:(NSString*)itemID\n{\n    //predicate\n    NSPredicate* predicate = [NSPredicate predicateWithFormat:@\"itemIdentifier == %@\", itemID];\n    \n    //item\n    NSToolbarItem* item = [[self.toolbar.items filteredArrayUsingPredicate:predicate] firstObject];\n    \n    //dbg msg\n    os_log_debug(logHandle, \"item '%@' -> %{public}@\", itemID, item);\n    \n    //select\n    [self toolbarButtonHandler:item];\n    [self.toolbar setSelectedItemIdentifier:itemID];\n    \n    return;\n}\n\n//toolbar view handler\n// toggle view based on user selection\n-(IBAction)toolbarButtonHandler:(id)sender\n{\n    //view\n    NSView* view = nil;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"%s invoked with %{public}@\", __PRETTY_FUNCTION__, sender);\n    \n    //when we've prev added a view\n    // remove the prev view cuz adding a new one\n    if(YES == self.viewWasAdded)\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"removing previous view...\");\n        \n        //remove\n        [[[self.window.contentView subviews] lastObject] removeFromSuperview];\n    }\n    \n    //assign view\n    switch(((NSToolbarItem*)sender).tag)\n    {\n        //rules\n        case TOOLBAR_RULES:\n            \n            //set view\n            view = self.rulesView;\n            \n            //show\n            self.showRulesButton.hidden = NO;\n            \n            //set 'apple allowed' button state\n            ((NSButton*)[view viewWithTag:BUTTON_ALLOW_APPLE]).state = [self.preferences[PREF_ALLOW_APPLE] boolValue];\n            \n            //set 'installed allowed' button state\n            ((NSButton*)[view viewWithTag:BUTTON_ALLOW_INSTALLED]).state = [self.preferences[PREF_ALLOW_INSTALLED] boolValue];\n            \n            //set 'allow dns' button state\n            ((NSButton*)[view viewWithTag:BUTTON_ALLOW_DNS]).state = [self.preferences[PREF_ALLOW_DNS] boolValue];\n            \n            //set 'allow localhost' button state\n            ((NSButton*)[view viewWithTag:BUTTON_ALLOW_LOCALHOST]).state = [self.preferences[PREF_ALLOW_LOCALHOST] boolValue];\n            \n            //set 'allow simulator apps' button\n            ((NSButton*)[view viewWithTag:BUTTON_ALLOW_SIMULATOR]).state = [self.preferences[PREF_ALLOW_SIMULATOR] boolValue];\n\n            break;\n            \n        //modes\n        case TOOLBAR_MODES:\n            \n            //set view\n            view = self.modesView;\n            \n            //set 'passive mode' button state\n            ((NSButton*)[view viewWithTag:BUTTON_PASSIVE_MODE]).state = [self.preferences[PREF_PASSIVE_MODE] boolValue];\n            \n            //set 'passive mode' action\n            [self.passiveModeAction selectItemAtIndex: [self.preferences[PREF_PASSIVE_MODE_ACTION] integerValue]];\n            \n            //set 'passive mode' rules\n            [self.passiveModeRules selectItemAtIndex: [self.preferences[PREF_PASSIVE_MODE_RULES] integerValue]];\n            \n            //set 'block mode' button state\n            ((NSButton*)[view viewWithTag:BUTTON_BLOCK_MODE]).state = [self.preferences[PREF_BLOCK_MODE] boolValue];\n            \n            //set 'no icon' button state\n            ((NSButton*)[view viewWithTag:BUTTON_NO_ICON_MODE]).state = [self.preferences[PREF_NO_ICON_MODE] boolValue];\n            \n            //set 'no VT icon' button state\n            ((NSButton*)[view viewWithTag:BUTTON_NO_VT_MODE]).state = [self.preferences[PREF_NO_VT_MODE] boolValue];\n            \n            break;\n            \n        //lists\n        case TOOLBAR_LISTS:\n            \n            //set view\n            view = self.listsView;\n            \n            //set 'allow list' button state\n            ((NSButton*)[view viewWithTag:BUTTON_USE_ALLOW_LIST]).state = [self.preferences[PREF_USE_ALLOW_LIST] boolValue];\n            \n            //is there a allow list? ...set!\n            if(0 != [self.preferences[PREF_ALLOW_LIST] length])\n            {\n                //set\n                self.allowList.stringValue = self.preferences[PREF_ALLOW_LIST];\n            }\n            \n            //set 'browse' button state\n            self.selectAllowListButton.enabled = [self.preferences[PREF_USE_ALLOW_LIST] boolValue];\n            \n            //set allow list input state\n            self.allowList.enabled = [self.preferences[PREF_USE_ALLOW_LIST] boolValue];\n            \n            //set 'block list' button state\n            ((NSButton*)[view viewWithTag:BUTTON_USE_BLOCK_LIST]).state = [self.preferences[PREF_USE_BLOCK_LIST] boolValue];\n            \n            //is there a block list? ...set!\n            if(0 != [self.preferences[PREF_BLOCK_LIST] length])\n            {\n                //set\n                self.blockList.stringValue = self.preferences[PREF_BLOCK_LIST];\n            }\n            \n            //set 'browse' button state\n            self.selectBlockListButton.enabled = [self.preferences[PREF_USE_BLOCK_LIST] boolValue];\n            \n            //set block list input state\n            self.blockList.enabled = [self.preferences[PREF_USE_BLOCK_LIST] boolValue];\n            \n            break;\n            \n        //profiles\n        case TOOLBAR_PROFILES:\n            \n            //set view\n            view = self.profilesView;\n            \n            //send XPC msg to daemon get profiles\n            self.profiles = [xpcDaemonClient getProfiles];\n            \n            //manually add default at start\n            [self.profiles insertObject:@\"Default\" atIndex:0];\n            \n            //dbg msg\n            os_log_debug(logHandle, \"list of profiles: %{public}@\", self.profiles);\n            \n            //reload table\n            [self.profilesTable reloadData];\n            \n            break;\n            \n        //update\n        case TOOLBAR_UPDATE:\n            \n            //set view\n            view = self.updateView;\n    \n            //set 'update' button state\n            ((NSButton*)[view viewWithTag:BUTTON_NO_UPDATE_MODE]).state = [self.preferences[PREF_NO_UPDATE_MODE] boolValue];\n            \n            //show\n            self.updateButton.hidden = NO;\n            \n            //(re)set update label\n            self.updateLabel.stringValue = @\"\";\n            \n            break;\n            \n        default:\n            return;\n    }\n\n    // Resize window to fit the view’s height (keeping top edge fixed)\n    NSRect windowFrame = self.window.frame;\n    CGFloat newHeight = view.frame.size.height + 50 + 10; //toolbar + a bit extra\n    CGFloat newWidth = view.frame.size.width;\n    CGFloat deltaY = NSMaxY(windowFrame) - newHeight;\n    [self.window setFrame:NSMakeRect(windowFrame.origin.x, deltaY, newWidth, newHeight) display:YES];\n\n    // Position view so its top aligns with the window’s contentView top\n    NSView *container = self.window.contentView;\n    NSRect viewFrame = view.frame;\n    viewFrame.origin.y = container.bounds.size.height - viewFrame.size.height;\n    viewFrame.origin.x = 0;\n    view.frame = viewFrame;\n    \n    //add to window\n    [self.window.contentView addSubview:view];\n    \n    //set\n    self.viewWasAdded = YES;\n    \nbail:\n    \n    return;\n}\n\n//invoked when user toggles button\n// update preferences for that button/item\n-(IBAction)togglePreference:(id)sender\n{\n    //preferences\n    NSMutableDictionary* updatedPreferences = nil;\n    \n    //button state\n    NSNumber* state = nil;\n    \n    //in \"add profile\" mode\n    // want to capture all the preferences\n    if(YES == self.addProfileSheet.isVisible)\n    {\n        updatedPreferences = self.profilePreferences;\n    }\n    //otherwise\n    // grab (just) updated preferences to send to daemon\n    else\n    {\n        //init\n        updatedPreferences = [NSMutableDictionary dictionary];\n    }\n    \n    //get button state\n    state = [NSNumber numberWithBool:((NSButton*)sender).state];\n    \n    //set appropriate preference\n    switch(((NSButton*)sender).tag)\n    {\n        //allow apple\n        case BUTTON_ALLOW_APPLE:\n            updatedPreferences[PREF_ALLOW_APPLE] = state;\n            break;\n            \n        //allow installed\n        case BUTTON_ALLOW_INSTALLED:\n            updatedPreferences[PREF_ALLOW_INSTALLED] = state;\n            break;\n        \n        //allow dns traffic\n        case BUTTON_ALLOW_DNS:\n            updatedPreferences[PREF_ALLOW_DNS] = state;\n            break;\n            \n        //allow localhost host\n        case BUTTON_ALLOW_LOCALHOST:\n            updatedPreferences[PREF_ALLOW_LOCALHOST] = state;\n            break;\n            \n        //allow simulator apps\n        case BUTTON_ALLOW_SIMULATOR:\n            updatedPreferences[PREF_ALLOW_SIMULATOR] = state;\n            break;\n            \n        //use block list\n        case BUTTON_USE_ALLOW_LIST:\n            \n            //set state\n            updatedPreferences[PREF_USE_ALLOW_LIST] = state;\n            \n            //disable?\n            // remove allow list too\n            if(NSControlStateValueOff == state.longValue)\n            {\n                //unset\n                updatedPreferences[PREF_ALLOW_LIST] = @\"\";\n                \n                //clear\n                self.allowList.stringValue = @\"\";\n            }\n            \n            //set allow list input state\n            self.allowList.enabled = (NSControlStateValueOn == state.longValue);\n            \n            //set 'browse' button state\n            self.selectAllowListButton.enabled = (NSControlStateValueOn == state.longValue);\n            \n            break;\n            \n        //use block list\n        case BUTTON_USE_BLOCK_LIST:\n            \n            //set\n            updatedPreferences[PREF_USE_BLOCK_LIST] = state;\n            \n            //disable?\n            // remove block list too\n            if(NSControlStateValueOff == state.longValue)\n            {\n                //unset\n                updatedPreferences[PREF_BLOCK_LIST] = @\"\";\n                \n                //clear\n                self.blockList.stringValue = @\"\";\n            }\n            \n            //set block list input state\n            self.blockList.enabled = (NSControlStateValueOn == state.longValue);\n            \n            //set 'browse' button state\n            self.selectBlockListButton.enabled = (NSControlStateValueOn == state.longValue);\n            \n            break;\n            \n        //passive mode\n        case BUTTON_PASSIVE_MODE:\n            \n            //grab state\n            updatedPreferences[PREF_PASSIVE_MODE] = state;\n            \n            //grab selected item of action\n            updatedPreferences[PREF_PASSIVE_MODE_ACTION] = [NSNumber numberWithInteger:self.passiveModeAction.indexOfSelectedItem];\n            \n            //grab selected item of rules\n            updatedPreferences[PREF_PASSIVE_MODE_RULES] = [NSNumber numberWithInteger:self.passiveModeRules.indexOfSelectedItem];\n            \n            break;\n            \n        //block mode\n        case BUTTON_BLOCK_MODE:\n            updatedPreferences[PREF_BLOCK_MODE] = state;\n            \n            //enable?\n            // show alert\n            if(NSControlStateValueOn == state.longValue)\n            {\n                //show alert\n                showAlert(NSAlertStyleInformational, NSLocalizedString(@\"Outgoing traffic will now be blocked.\",@\"Outgoing traffic will now be blocked.\"), NSLocalizedString(@\"Note however:\\r\\n▪ Existing connections will not be impacted.\\r\\n▪ OS traffic (not routed thru LuLu) will not be blocked.\",@\"Note however:\\r\\n▪ Existing connections will not be impacted.\\r\\n▪ OS traffic (not routed thru LuLu) will not be blocked.\"), @[NSLocalizedString(@\"OK\", @\"OK\")]);\n            }\n            \n            break;\n            \n        //no icon mode\n        case BUTTON_NO_ICON_MODE:\n            updatedPreferences[PREF_NO_ICON_MODE] = state;\n            break;\n            \n        //no vt mode\n        case BUTTON_NO_VT_MODE:\n            updatedPreferences[PREF_NO_VT_MODE] = state;\n            break;\n            \n        //no update mode\n        case BUTTON_NO_UPDATE_MODE:\n            updatedPreferences[PREF_NO_UPDATE_MODE] = state;\n            break;\n            \n        default:\n            break;\n    }\n    \n    //logic for 'passive mode' action\n    if(YES == [sender isEqualTo:self.passiveModeAction])\n    {\n        //grab selected index\n        updatedPreferences[PREF_PASSIVE_MODE_ACTION] = [NSNumber numberWithInteger:self.passiveModeAction.indexOfSelectedItem];\n    }\n    //logic for 'passive mode' rules\n    else if(YES == [sender isEqualTo:self.passiveModeRules])\n    {\n        //grab selected index\n        updatedPreferences[PREF_PASSIVE_MODE_RULES] = [NSNumber numberWithInteger:self.passiveModeRules.indexOfSelectedItem];\n    }\n    \n    //only process here if we're not in \"add profile\" mode\n    if(YES != self.addProfileSheet.isVisible)\n    {\n        //send XPC msg to daemon to update prefs\n        // returns (all/latest) prefs, which is what we want\n        self.preferences = [xpcDaemonClient updatePreferences:updatedPreferences];\n\n        //call back into app to process\n        // e.g. show/hide status bar icon, etc.\n        [((AppDelegate*)[[NSApplication sharedApplication] delegate]) preferencesChanged:self.preferences];\n    }\n    \n    return;\n}\n\n//browse for select list\n-(IBAction)selectBlockOrAllowList:(id)sender\n{\n    //'browse' panel\n    NSOpenPanel *panel = nil;\n        \n    //init panel\n    panel = [NSOpenPanel openPanel];\n        \n    //allow files\n    panel.canChooseFiles = YES;\n    \n    //start ...at desktop\n    panel.directoryURL = [NSURL fileURLWithPath:[NSSearchPathForDirectoriesInDomains (NSDesktopDirectory, NSUserDomainMask, YES) firstObject]];\n        \n    //disable multiple selections\n    panel.allowsMultipleSelection = NO;\n        \n    //show it\n    // and wait for response\n    if(NSModalResponseOK == [panel runModal])\n    {\n        //allow list\n        if(sender == self.selectAllowListButton)\n        {\n            //update ui\n            self.allowList.stringValue = panel.URL.path;\n            \n            //dbg msg\n            os_log_debug(logHandle, \"user selected allow list: %{public}@\", self.allowList.stringValue);\n            \n            //send XPC msg to daemon to update prefs\n            self.preferences = [xpcDaemonClient updatePreferences:@{PREF_ALLOW_LIST:panel.URL.path}];\n        }\n        //block list\n        else if(sender == self.selectBlockListButton)\n        {\n            //update ui\n            self.blockList.stringValue = panel.URL.path;\n            \n            //dbg msg\n            os_log_debug(logHandle, \"user selected block list: %{public}@\", self.blockList.stringValue);\n            \n            //send XPC msg to daemon to update prefs\n            self.preferences = [xpcDaemonClient updatePreferences:@{PREF_BLOCK_LIST:panel.URL.path}];\n        }\n        //error\n        else\n        {\n            //err msg\n            os_log_error(logHandle, \"ERROR: %{public}@ is an invalid sender\", sender);\n        }\n    }\n    \n    return;\n}\n\n//invoked when block list path is (manually entered)\n-(IBAction)updateBlockList:(id)sender\n{\n    //dbg msg\n    os_log_debug(logHandle, \"got 'update block list event' (value: %{public}@)\", self.blockList.stringValue);\n    \n    //send XPC msg to daemon to update prefs\n    // returns (all/latest) prefs, which is what we want\n    self.preferences = [xpcDaemonClient updatePreferences:@{PREF_BLOCK_LIST:self.blockList.stringValue}];\n    \n    return;\n}\n\n//reload current toolbar view (as profile changed)\n// ...by triggering a 'click' to our toolbar button handler\n-(void)reload\n{\n    //dbg msg\n    os_log_debug(logHandle, \"%s invoked\", __PRETTY_FUNCTION__);\n    \n    //grab (profile's) preferences\n    self.preferences = [xpcDaemonClient getPreferences];\n    \n    //(re)set subtitle\n    [self setSubTitle];\n    \n    //selected ID\n    NSToolbarItemIdentifier selectedID = self.toolbar.selectedItemIdentifier;\n\n    //selected item\n    NSToolbarItem* toolbarItem = [[self.toolbar items]\n        filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@\"itemIdentifier == %@\", selectedID]].firstObject;\n\n    //trigger reload\n    [self toolbarButtonHandler:toolbarItem];\n    \n    return;\n}\n\n#pragma mark – Profile's table delegates\n\n//number of profiles\n- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView {\n    return self.profiles.count;\n}\n\n//view for each column + row\n- (NSView *)tableView:(NSTableView *)tableView\n   viewForTableColumn:(NSTableColumn *)tableColumn\n                  row:(NSInteger)row\n{\n    //dequeue a cell\n    NSTableCellView *cell = [tableView makeViewWithIdentifier:tableColumn.identifier owner:self];\n    \n    //first column\n    // check button if we're looking at the current profile\n    if(YES == [tableColumn.identifier isEqualToString:@\"Current\"]) {\n        \n        //current profile\n        NSString* currentProfile = [xpcDaemonClient getCurrentProfile];\n        \n        //select button\n        NSButton* selectButton = (NSButton*)[cell viewWithTag:TABLE_ROW_SELECT_BTN_TAG];\n        \n        //dbg msg\n        os_log_debug(logHandle, \"current row: %ld, current profile %{public}@, select button: %{public}@\", (long)row, currentProfile, selectButton);\n        \n        //no profile?\n        // select button/row zero (default)\n        if( (0 == row) &&\n            (nil == currentProfile) )\n        {\n            //dbg msg\n            os_log_debug(logHandle, \"enabling default button here...\");\n            \n            //select\n            selectButton.state = NSControlStateValueOn;\n            \n            //select row too\n            [tableView selectRowIndexes:[NSIndexSet indexSetWithIndex:row] byExtendingSelection:NO];\n        }\n        //profile matches current?\n        else if(YES == [currentProfile isEqualToString:self.profiles[row]])\n        {\n            //dbg msg\n            os_log_debug(logHandle, \"match, enabling button here...\");\n            \n            //select\n            selectButton.state = NSControlStateValueOn;\n            \n            //select row too\n            [tableView selectRowIndexes:[NSIndexSet indexSetWithIndex:row] byExtendingSelection:NO];\n        }\n        else\n        {\n            //turn off\n            selectButton.state = NSControlStateValueOff;\n        }\n    }\n    \n    //add name\n    // and customize delete button\n    if ([tableColumn.identifier isEqualToString:@\"Name\"]) {\n        \n        //delete button\n        NSButton* deleteButton = (NSButton*)[cell viewWithTag:TABLE_ROW_DELETE_BTN_TAG];\n        \n        //add name\n        cell.textField.stringValue = self.profiles[row];\n        \n        //first row?\n        // this is 'default' profile, so disable delete button\n        if(0 == row) {\n            \n            //hide\n            deleteButton.hidden = YES;\n            \n        } else {\n            \n            //show/enable\n            deleteButton.hidden = NO;\n            deleteButton.enabled = YES;\n        }\n    }\n\n    return cell;\n}\n\n#pragma mark – Profile's button handlers\n\n//get profile name from current/selected row\n-(NSString*)profileFromTable:(id)sender\n{\n    //profile path\n    NSString* profile = nil;\n    \n    //index of row\n    // either clicked or selected row\n    NSInteger row = 0;\n\n    //dbg msg\n    os_log_debug(logHandle, \"%s invoked\", __PRETTY_FUNCTION__);\n    \n    //get row\n    if(nil != sender)\n    {\n        //row from sender\n        row = [self.profilesTable rowForView:sender];\n    }\n    //otherwise get selected row\n    else\n    {\n        //selected row\n        row = self.profilesTable.selectedRow;\n    }\n    \n    //get profile\n    // index 0, is the default profile, which we want as nil\n    if(row > 0 && row < self.profiles.count)\n    {\n        //get profile\n        profile = self.profiles[row];\n    }\n    \n    //dbg msg\n    os_log_debug(logHandle, \"row: %ld, profile: %{public}@\", (long)row, profile);\n    \n    return profile;\n}\n\n//'switch profile' button handler\n-(IBAction)switchProfile:(id)sender {\n    \n    //profile\n    NSString* profile = nil;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"%s invoked\", __PRETTY_FUNCTION__);\n    \n    //get profile\n    // can be 'nil' if default profile is selected\n    profile = [self profileFromTable:sender];\n    \n    //dbg msg\n    os_log_debug(logHandle, \"user wants to change profile to '%{public}@'\", profile ? profile : @\"Default\");\n    \n    //set profile via XPC\n    [xpcDaemonClient setProfile:profile];\n    \n    //tell app profiles changed\n    // will grab profile's preferences too\n    [((AppDelegate*)[[NSApplication sharedApplication] delegate]) profilesChanged];\n\n    //also tell app preferences changed\n    [((AppDelegate*)[[NSApplication sharedApplication] delegate]) preferencesChanged:self.preferences];\n    \n    //show alert\n    showAlert(NSAlertStyleInformational, NSLocalizedString(@\"Profile Switched\", @\"Profile Switched\"), [NSString stringWithFormat:NSLocalizedString(@\"Current profile is now: '%@'.\", @\"Current profile is now: '%@'.\"), nil != profile ? profile : NSLocalizedString(@\"Default\", @\"Default\")], @[NSLocalizedString(@\"OK\", @\"OK\")]);\n    \n    return;\n}\n\n//add profile button handler\n// show sheet for user to specify settings\n-(IBAction)addProfile:(id)sender {\n    \n    //dbg msg\n    os_log_debug(logHandle, \"%s invoked\", __PRETTY_FUNCTION__);\n    \n    //init dictionary to collect preferences\n    self.profilePreferences = [NSMutableDictionary dictionary];\n    \n    //init/reset\n    self.profileName = nil;\n    \n    //init/reset\n    self.continueProfileButton.tag = 0;\n    \n    //remove any old view\n    if(self.currentProfileSubview) {\n        \n        //remove current view\n        [self.currentProfileSubview removeFromSuperview];\n    }\n\n    //init current view (with profile name)\n    self.currentProfileSubview = self.profileNameView;\n    \n    //add initial (profile name) view\n    [self.addProfileSheet.contentView addSubview:self.currentProfileSubview];\n    \n    //disable autoresizing mask\n    self.currentProfileSubview.translatesAutoresizingMaskIntoConstraints = NO;\n\n    //pin to top, leading, and trailing edges\n    [NSLayoutConstraint activateConstraints:@[\n        [self.currentProfileSubview.topAnchor constraintEqualToAnchor:self.addProfileSheet.contentView.topAnchor],\n        [self.currentProfileSubview.leadingAnchor constraintEqualToAnchor:self.addProfileSheet.contentView.leadingAnchor],\n        [self.currentProfileSubview.trailingAnchor constraintEqualToAnchor:self.addProfileSheet.contentView.trailingAnchor]\n    ]];\n    \n    //reset button name\n    self.continueProfileButton.title = NSLocalizedString(@\"Next\", @\"Next\");\n    \n    //set profile name\n    self.profileNameLabel.stringValue = @\"\";\n    \n    //show sheet for user to add profile\n    [self.window beginSheet:self.addProfileSheet\n               completionHandler:^(NSModalResponse returnCode) {\n        \n            //add profile?\n            // and handle UI refreshes, etc\n            if (returnCode == NSModalResponseOK) {\n            \n                //dbg msg\n                os_log_debug(logHandle, \"user wants to add profile '%{public}@'\", self.profileName);\n                \n                //add profile via XPC\n                [xpcDaemonClient addProfile:self.profileName preferences:self.profilePreferences];\n                \n                //hide profile sheet\n                [self.addProfileSheet orderOut:self];\n                \n                //tell app profiles changed\n                // will grab profile's preferences too\n                [((AppDelegate*)[[NSApplication sharedApplication] delegate]) profilesChanged];\n                \n                //tell app preferences changed\n                [((AppDelegate*)[[NSApplication sharedApplication] delegate]) preferencesChanged:self.preferences];\n                \n                //show alert\n                showAlert(NSAlertStyleInformational, NSLocalizedString(@\"Added Profile\", @\"Added Profile\"), [NSString stringWithFormat:NSLocalizedString(@\"New profile '%@' saved and activated.\", @\"New profile '%@' saved and activated.\"), self.profileName], @[NSLocalizedString(@\"OK\", @\"OK\")]);\n            }\n            \n            //cancel\n            else {\n                \n                //close sheet\n                [self.addProfileSheet orderOut:self];\n            }\n    }];\n    \n    return;\n}\n\n//cancel creation of profile\n- (IBAction)cancelProfileButtonHandler:(id)sender {\n    \n    //end w/ cancel\n    [self.window endSheet:self.addProfileSheet returnCode:NSModalResponseCancel];\n    \n    return;\n}\n\n//show next view\n// note: each case is current view, going to next!\n-(IBAction)continueProfileButtonHandler:(NSButton*)sender {\n    \n    //switch on current view\n    // last view, will add the profile\n    switch (sender.tag) {\n            \n        //current view: name\n        // setup next view: rules\n        case profileName:\n        {\n            //check against empty\n            if(!self.profileNameLabel.stringValue.length)\n            {\n                //show alert\n                showAlert(NSAlertStyleInformational, NSLocalizedString(@\"Invalid Profile Name\", @\"Invalid Profile Name\"), NSLocalizedString(@\"Profile name can't be blank\", @\"Profile name can't be blank\"), @[NSLocalizedString(@\"OK\", @\"OK\")]);\n                \n                self.profileNameLabel.stringValue = @\"\";\n                goto bail;\n            }\n            \n            //check against 'Default'\n            if(NSOrderedSame == [self.profileNameLabel.stringValue caseInsensitiveCompare:NSLocalizedString(@\"Default\", @\"Default\")])\n            {\n                //show alert\n                showAlert(NSAlertStyleInformational, NSLocalizedString(@\"Invalid Profile Name\", @\"Invalid Profile Name\"), NSLocalizedString(@\"'Default' is a reserved profile name.\", @\"'Default' is a reserved profile name.\"), @[NSLocalizedString(@\"OK\", @\"OK\")]);\n                \n                goto bail;\n            }\n            \n            //check against existing names\n            for(NSString *name in [xpcDaemonClient getProfiles])\n            {\n                if(NSOrderedSame == [self.profileNameLabel.stringValue caseInsensitiveCompare:name])\n                {\n                    //show alert\n                    showAlert(NSAlertStyleInformational, NSLocalizedString(@\"Invalid Profile Name\", @\"Invalid Profile Name\"), [NSString stringWithFormat:NSLocalizedString(@\"'%@' matches an existing profile name.\", @\"'%@' matches an existing profile name.\"), name], @[NSLocalizedString(@\"OK\", @\"OK\")]);\n                    \n                    self.profileNameLabel.stringValue = @\"\";\n                    goto bail;\n                }\n            }\n            \n            //save name\n            self.profileName = self.profileNameLabel.stringValue;\n            \n            //remove current view\n            [self.currentProfileSubview removeFromSuperview];\n            \n            //update\n            self.currentProfileSubview = self.rulesView;\n            \n            //hide 'show buttons'\n            self.showRulesButton.hidden = YES;\n            \n            //add to rule's view\n            [self.addProfileSheet.contentView addSubview:self.currentProfileSubview];\n            \n            //update tag\n            self.continueProfileButton.tag = profileRules;\n            \n            break;\n        }\n            \n        //current view: rules\n        // setup next view: modes\n        case profileRules:\n            \n            //remove current view\n            [self.currentProfileSubview removeFromSuperview];\n            \n            //update\n            self.currentProfileSubview = self.modesView;\n            \n            //add to mode's view\n            [self.addProfileSheet.contentView addSubview:self.currentProfileSubview];\n            \n            //update tag\n            self.continueProfileButton.tag = profileModes;\n            \n            break;\n        \n        //current view: modes\n        // setup next view: lists\n        case profileModes:\n            \n            //remove current view\n            [self.currentProfileSubview removeFromSuperview];\n            \n            //update\n            self.currentProfileSubview = self.listsView;\n            \n            //add to list's view\n            [self.addProfileSheet.contentView addSubview:self.currentProfileSubview];\n            \n            //update tag\n            self.continueProfileButton.tag = profileLists;\n            \n            break;\n        \n        //current view: lists\n        // setup next view: updates\n        case profileLists:\n            \n            //remove current view\n            [self.currentProfileSubview removeFromSuperview];\n            \n            //update\n            self.currentProfileSubview = self.updateView;\n            \n            //hide button\n            self.updateButton.hidden = YES;\n            \n            //unset label\n            self.updateLabel.stringValue = @\"\";\n            \n            //add to mode's view\n            [self.addProfileSheet.contentView addSubview:self.currentProfileSubview];\n            \n            //update tag\n            self.continueProfileButton.tag = profileUpdates;\n            \n            //update button name to \"Add Profile\"\n            self.continueProfileButton.title = NSLocalizedString(@\"Add Profile\", @\"Add Profile\");\n            \n            break;\n            \n        //current view: updates\n        // add profile as this is the last one!\n        case profileUpdates:\n            \n            //end with 'ok'\n            [self.window endSheet:self.addProfileSheet returnCode:NSModalResponseOK];\n            \n        default:\n            break;\n    }\n    \n    //uncheck all checks buttons (might be set from current preferences)\n    for (NSView *subview in self.currentProfileSubview.subviews) {\n        if ([subview isKindOfClass:[NSButton class]]) {\n            NSButton *button = (NSButton *)subview;\n            // Uncheck only if the button has a toggleable state\n                if (button.allowsMixedState || button.state != NSControlStateValueOff) {\n                    button.state = NSControlStateValueOff;\n                }\n        }\n    }\n    \n    //update view's fame\n    NSRect bounds = self.addProfileSheet.contentView.bounds;\n    NSRect frame = self.currentProfileSubview.frame;\n    frame.origin.x  = 0;\n    frame.origin.y  = bounds.size.height - frame.size.height;\n    \n    //set frame\n    self.currentProfileSubview.frame = frame;\n    \nbail:\n\n    return;\n}\n\n//delete profile button handler\n-(IBAction)deleteProfile:(id)sender {\n    \n    //response\n    NSModalResponse response = 0;\n    \n    //name\n    NSString* profile = nil;\n\n    //get profile\n    profile = [self profileFromTable:sender];\n    \n    //dbg msg\n    os_log_debug(logHandle, \"user wants to delete profile '%{public}@'\", profile);\n    \n    //show alert\n    response = showAlert(NSAlertStyleInformational, NSLocalizedString(@\"Confirm Deletion\", @\"Confirm Deletion\"), [NSString stringWithFormat:NSLocalizedString(@\"Delete profile: '%@'?\", @\"Delete profile: '%@'?\"), profile], @[NSLocalizedString(@\"Ok\", @\"Ok\"), NSLocalizedString(@\"Cancel\", @\"Cancel\")]);\n    \n    //cancel?\n    if(NSAlertSecondButtonReturn == response)\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"user canceled deleting profile...\");\n        \n        //done\n        goto bail;\n    }\n    \n    //delete via XPC\n    [xpcDaemonClient deleteProfile:profile];\n    \n    //dbg msg\n    os_log_debug(logHandle, \"deleted profile '%{public}@'\", profile);\n    \n    //tell app profiles changed\n    // will grab profile's preferences too\n    [((AppDelegate*)[[NSApplication sharedApplication] delegate]) profilesChanged];\n    \n    //tell app preferences (maybe) changed\n    [((AppDelegate*)[[NSApplication sharedApplication] delegate]) preferencesChanged:self.preferences];\n    \nbail:\n    \n    return;\n}\n\n//'check for update' button handler\n-(IBAction)check4Update:(id)sender\n{\n    //update obj\n    Update* update = nil;\n    \n    //disable button\n    self.updateButton.enabled = NO;\n    \n    //reset\n    self.updateLabel.stringValue = @\"\";\n    \n    //show/start spinner\n    [self.updateIndicator startAnimation:self];\n    \n    //init update obj\n    update = [[Update alloc] init];\n    \n    //check\n    // but after a delay for UI\n    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.75 * NSEC_PER_SEC), dispatch_get_main_queue(),\n    ^{\n        //check for update\n        [update checkForUpdate:^(NSUInteger result, NSString* newVersion) {\n            \n            //process response\n            [self updateResponse:result newVersion:newVersion];\n            \n        }];\n    });\n    \n    return;\n}\n\n//'view rules' button handler\n// call helper method to show rule's window\n-(IBAction)viewRules:(id)sender\n{\n    //call into app delegate to show app rules\n    [((AppDelegate*)[[NSApplication sharedApplication] delegate]) showRules:nil];\n    \n    return;\n}\n\n//process update response\n// error, no update, update/new version\n-(void)updateResponse:(NSInteger)result newVersion:(NSString*)newVersion\n{\n    //re-enable button\n    self.updateButton.enabled = YES;\n    \n    //stop/hide spinner\n    [self.updateIndicator stopAnimation:self];\n    \n    switch(result)\n    {\n        //error\n        case Update_Error:\n            \n            //set label\n            self.updateLabel.stringValue = NSLocalizedString(@\"error: update check failed\", @\"error: update check failed\");\n            break;\n            \n        //no updates\n        case Update_None:\n            \n            //dbg msg\n            os_log_debug(logHandle, \"no updates available\");\n            \n            //set label\n            self.updateLabel.stringValue = [NSString stringWithFormat:NSLocalizedString(@\"Installed version (%@),\\r\\nis the latest.\",@\"Installed version (%@),\\r\\nis the latest.\"), getAppVersion()];\n           \n            break;\n            \n        //update is not compatible\n        case Update_NotSupported:\n            \n            //dbg msg\n            os_log_debug(logHandle, \"update available, but isn't supported on macOS %ld.%ld\", NSProcessInfo.processInfo.operatingSystemVersion.majorVersion, NSProcessInfo.processInfo.operatingSystemVersion.minorVersion);\n            \n            //set label\n            self.updateLabel.stringValue = [NSString stringWithFormat:NSLocalizedString(@\"Update available, but isn't supported on macOS %ld.%ld\", @\"Update available, but isn't supported on macOS %ld.%ld\"), NSProcessInfo.processInfo.operatingSystemVersion.majorVersion, NSProcessInfo.processInfo.operatingSystemVersion.minorVersion];\n           \n            break;\n         \n        //new version\n        case Update_Available:\n            \n            //dbg msg\n            os_log_debug(logHandle, \"a new version (%@) is available\", newVersion);\n            \n            //alloc update window\n            updateWindowController = [[UpdateWindowController alloc] initWithWindowNibName:@\"UpdateWindow\"];\n            \n            //configure\n            [self.updateWindowController configure:[NSString stringWithFormat:NSLocalizedString(@\"a new version (%@) is available!\",@\"a new version (%@) is available!\"), newVersion]];\n            \n            //center window\n            [[self.updateWindowController window] center];\n            \n            //show it\n            [self.updateWindowController showWindow:self];\n            \n            //invoke function in background that will make window modal\n            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{\n                \n                //make modal\n                makeModal(self.updateWindowController);\n                \n            });\n            \n            break;\n    }\n    \n    return;\n}\n\n//button handler\n// open LuLu home page/docs\n-(IBAction)openHomePage:(id)sender {\n    \n    //open\n    [NSWorkspace.sharedWorkspace openURL:[NSURL URLWithString:PRODUCT_URL]];\n    \n    return;\n}\n\n//on window close\n// update prefs/set activation policy\n-(void)windowWillClose:(NSNotification *)notification\n{\n    //blank allow list?\n    // uncheck 'enabled' and update prefs\n    if(0 == self.allowList.stringValue.length)\n    {\n        //uncheck 'allow list' radio button\n        ((NSButton*)[self.listsView viewWithTag:BUTTON_USE_ALLOW_LIST]).state = NSControlStateValueOff;\n        \n        //disable 'browse' button\n        self.selectAllowListButton.enabled = NSControlStateValueOff;\n        \n        //clear allow list\n        self.allowList.stringValue = @\"\";\n        \n        //disable allow list input\n        self.allowList.enabled = NSControlStateValueOff;\n        \n        //send XPC msg to daemon to update prefs\n        self.preferences = [xpcDaemonClient updatePreferences:@{PREF_USE_ALLOW_LIST:@0, PREF_ALLOW_LIST:@\"\"}];\n    }\n    \n    //allow list changed? capture!\n    // this logic is needed, as window can be closed when text field still has focus and 'end edit' won't have fired\n    else if(YES != [self.preferences[PREF_ALLOW_LIST] isEqualToString:self.allowList.stringValue])\n    {\n        //send XPC msg to daemon to update prefs\n        self.preferences = [xpcDaemonClient updatePreferences:@{PREF_ALLOW_LIST:self.allowList.stringValue}];\n    }\n    \n    //blank block list?\n    // uncheck 'enabled' and update prefs\n    if(0 == self.blockList.stringValue.length)\n    {\n        //uncheck 'blocklist' radio button\n        ((NSButton*)[self.listsView viewWithTag:BUTTON_USE_BLOCK_LIST]).state = NSControlStateValueOff;\n        \n        //disable 'browse' button\n        self.selectBlockListButton.enabled = NSControlStateValueOff;\n        \n        //clear block list\n        self.blockList.stringValue = @\"\";\n        \n        //disable block list input\n        self.blockList.enabled = NSControlStateValueOff;\n        \n        //send XPC msg to daemon to update prefs\n        self.preferences = [xpcDaemonClient updatePreferences:@{PREF_USE_BLOCK_LIST:@0, PREF_BLOCK_LIST:@\"\"}];\n    }\n        \n    //block list changed? capture!\n    // this logic is needed, as window can be closed when text field still has focus and 'end edit' won't have fired\n    else if(YES != [self.preferences[PREF_BLOCK_LIST] isEqualToString:self.blockList.stringValue])\n    {\n        //send XPC msg to daemon to update prefs\n        // returns (all/latest) prefs, which is what we want\n        self.preferences = [xpcDaemonClient updatePreferences:@{PREF_BLOCK_LIST:self.blockList.stringValue}];\n    }\n     \n    //wait a bit, then set activation policy\n    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),\n    ^{\n         //on main thread\n         dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{\n             \n             //set activation policy\n             [((AppDelegate*)[[NSApplication sharedApplication] delegate]) setActivationPolicy];\n             \n         });\n    });\n    \n    return;\n}\n@end\n"
  },
  {
    "path": "LuLu/App/RuleRow.h",
    "content": "//\n//  file: RuleRow.h\n//  project: lulu (main app)\n//  description: row for 'rules' table (header)\n//\n//  created by Patrick Wardle\n//  copyright (c) 2017 Objective-See. All rights reserved.\n//\n\n@import Cocoa;\n\n@interface RuleRow : NSTableRowView\n\n@end\n"
  },
  {
    "path": "LuLu/App/RuleRow.m",
    "content": "//\n//  file: RuleRow.m\n//  project: lulu (main app)\n//  description: row for 'rules' table\n//\n//  created by Patrick Wardle\n//  copyright (c) 2017 Objective-See. All rights reserved.\n//\n\n#import \"RuleRow.h\"\n\n@implementation RuleRow\n\n//custom row selection\n-(void)drawSelectionInRect:(NSRect)dirtyRect\n{\n    //selection rect\n    NSRect selectionRect = {0};\n    \n    //selection path\n    NSBezierPath* selectionPath = nil;\n    \n    //selection color\n    NSColor* selectionColor = nil;\n    \n    //highlight selected rows\n    if(self.selectionHighlightStyle != NSTableViewSelectionHighlightStyleNone)\n    {\n        //make selection rect\n        selectionRect = NSInsetRect(self.bounds, 2.5, 2.5);\n        \n        //set color\n        selectionColor = [NSColor unemphasizedSelectedContentBackgroundColor];\n        \n        //set stroke\n        [selectionColor setStroke];\n        \n        //set fill\n        [selectionColor setFill];\n        \n        //create selection path\n        // with rounded corners (5x5)\n        selectionPath = [NSBezierPath bezierPathWithRoundedRect:selectionRect xRadius:5 yRadius:5];\n        \n        //fill\n        [selectionPath fill];\n        \n        //stroke\n        [selectionPath stroke];\n    }\n    \n    return;\n}\n\n@end\n"
  },
  {
    "path": "LuLu/App/RulesMenuController.h",
    "content": "//\n//  RulesMenuController.h\n//  LuLu\n//\n//  Created by Patrick Wardle on 1/30/24.\n//  Copyright © 2024 Objective-See. All rights reserved.\n//\n\n#ifndef RulesMenuController_h\n#define RulesMenuController_h\n\n@import Foundation;\n\n@interface RulesMenuController : NSObject\n\n/* METHODS */\n\n-(void)addRule;\n-(void)showRules;\n-(void)exportRules;\n-(BOOL)importRules;\n-(NSInteger)cleanupRules;\n\n@end\n\n#endif /* RulesMenuController_h */\n"
  },
  {
    "path": "LuLu/App/RulesMenuController.m",
    "content": "//\n//  RulesMenuController.m\n//  LuLu\n//\n//  Created by Patrick Wardle on 1/30/24.\n//  Copyright © 2024 Objective-See. All rights reserved.\n//\n\n#import \"consts.h\"\n#import \"utilities.h\"\n#import \"AppDelegate.h\"\n#import \"XPCDaemonClient.h\"\n#import \"RulesMenuController.h\"\n\n/* GLOBALS */\n\n//log handle\nextern os_log_t logHandle;\n\n//xpc for daemon comms\nextern XPCDaemonClient* xpcDaemonClient;\n\n@implementation RulesMenuController\n\n//show rules\n// call into app delegate to show rules window\n-(void)showRules\n{\n    //show rules\n    [((AppDelegate*)[[NSApplication sharedApplication] delegate]) showRules:nil];\n    \n    return;\n}\n\n//add rule\n// show rules, then call into app delegate to open add rule window\n-(void)addRule\n{\n    //add rules\n    [((AppDelegate*)[[NSApplication sharedApplication] delegate]).rulesWindowController addRule:nil];\n    \n    return;\n}\n\n//export rules\n// show panel then write out rules\n-(void)exportRules\n{\n    //count\n    __block NSUInteger count = 0;\n    \n    //rules\n    NSDictionary* rules = nil;\n    \n    //error\n    __block NSError* error = nil;\n    \n    //'browse' panel\n    NSSavePanel *panel = nil;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"exporting rules...\");\n    \n    //get rules\n    rules = [xpcDaemonClient getRules];\n    \n    //dbg msg\n    os_log_debug(logHandle, \"received %lu rules from daemon\", (unsigned long)rules.count);\n    \n    //init panel\n    panel = [NSSavePanel savePanel];\n    \n    //default to ~/Desktop\n    panel.directoryURL = [NSURL fileURLWithPath:[NSSearchPathForDirectoriesInDomains (NSDesktopDirectory, NSUserDomainMask, YES) firstObject]];\n    \n    //suggest file name\n    [panel setNameFieldStringValue:NSLocalizedString(@\"rules.json\", @\"rules.json\")];\n    \n    //customize w/ \"user only\" rules options\n    NSButton *userRulesOnly = [[NSButton alloc] initWithFrame:NSMakeRect(0, 0, 200, 24)];\n    [userRulesOnly setButtonType:NSButtonTypeSwitch];\n    userRulesOnly.title = NSLocalizedString(@\"Only export user created rules\", @\"Only export user created rules\");\n    userRulesOnly.state = NSControlStateValueOff;\n    [userRulesOnly sizeToFit];\n    \n    panel.accessoryView = userRulesOnly;\n    \n    //show panel\n    // completion handler will invoked when user clicks 'ok'\n    [panel beginWithCompletionHandler:^(NSInteger result) {\n        \n        //only need to handle 'ok'\n        if(NSModalResponseOK == result)\n        {\n            //only user rules?\n            BOOL exportUserOnly = (NSControlStateValueOn == userRulesOnly.state);\n            \n            //rules (as JSON)\n            NSMutableString* json = [NSMutableString string];\n            \n            //start\n            [json appendString:@\"{\"];\n            \n            //covert each rule (set)\n            for(NSString* key in rules.allKeys)\n            {\n                //flag\n                BOOL hasPersistentRule = NO;\n                \n                //flag\n                BOOL hasUserCreatedRule = NO;\n                \n                //rule set\n                NSDictionary* ruleSet = nil;\n                \n                //extract\n                ruleSet = rules[key];\n                \n                //for a given item\n                // check all rules for persistent or user created\n                for(Rule* rule in rules[key][KEY_RULES])\n                {\n                    //not temp?\n                    if(!hasPersistentRule && ![rule isTemporary]) {\n                        hasPersistentRule = YES;\n                    }\n                    \n                    //user created (non temp rule)\n                    if(!hasUserCreatedRule && [rule isUserCreated] && ![rule isTemporary]) {\n                        hasUserCreatedRule = YES;\n                    }\n                }\n                \n                //skip if all item's rules are temp\n                if(YES != hasPersistentRule) {\n                    continue;\n                }\n                \n                //when exporting only user rules\n                //skip if all item's rules are *not* user created\n                if(exportUserOnly && !hasUserCreatedRule) {\n                    continue;\n                }\n                \n                //add key\n                [json appendFormat:@\"\\\"%@\\\" : [\", key];\n                \n                //covert each rule\n                for(Rule* rule in rules[key][KEY_RULES])\n                {\n                    //skip temp\n                    if(YES == [rule isTemporary]) {\n                        continue;\n                    }\n                    \n                    //skip non user created\n                    if(exportUserOnly && ![rule isUserCreated]) {\n                        continue;\n                    }\n                        \n                    //append rule\n                    [json appendFormat:@\"{%@},\", [rule toJSON]];\n                    \n                    //inc\n                    count++;\n                }\n                \n                //remove last ','\n                if(YES == [json hasSuffix:@\",\"])\n                {\n                    //remove\n                    [json deleteCharactersInRange:NSMakeRange(json.length-1, 1)];\n                }\n                \n                //end\n                [json appendString:@\"],\"];\n            }\n            \n            //remove last ','\n            if(YES == [json hasSuffix:@\",\"])\n            {\n                //remove\n                [json deleteCharactersInRange:NSMakeRange(json.length-1, 1)];\n            }\n            \n            //end\n            [json appendString:@\"}\"];\n            \n            //write out (converted) rules\n            // then activate Finder and select file\n            if(YES == [json writeToURL:panel.URL atomically:NO encoding:NSUTF8StringEncoding error:&error])\n            {\n                //activate Finder\n                [NSWorkspace.sharedWorkspace selectFile:panel.URL.path inFileViewerRootedAtPath:@\"\"];\n            }\n            //error\n            else\n            {\n                //err msg\n                os_log_error(logHandle, \"ERROR: failed to save rules: %{public}@\", error);\n                \n                //show alert\n                showAlert(NSAlertStyleWarning, NSLocalizedString(@\"ERROR: Failed to export rules\",@\"ERROR: Failed to export rules\"), NSLocalizedString(@\"See log for (more) details\",@\"See log for (more) details\"), @[NSLocalizedString(@\"OK\", @\"OK\")]);\n            }\n        }\n    }];\n\n    return;\n}\n\n//import rules\n// show panel, read in rules, parse, send to daemon\n-(BOOL)importRules\n{\n    //flag\n    BOOL imported = NO;\n    \n    //flag\n    __block BOOL userOnlyImport = YES;\n    \n    //error\n    NSError* error = nil;\n    \n    //count\n    NSUInteger count = 0;\n    \n    //rules data\n    NSData* data = nil;\n    \n    //rules from disk\n    NSDictionary* importedRules = nil;\n    \n    //rules, as rules\n    NSMutableDictionary* newRules = nil;\n    \n    //archived rules\n    NSData* archivedRules = nil;\n    \n    //'browse' panel\n    NSOpenPanel *panel = nil;\n    \n    //response to 'browse' panel\n    NSInteger response = 0;\n    \n    //init panel\n    panel = [NSOpenPanel openPanel];\n    \n    //allow files\n    panel.canChooseFiles = YES;\n    \n    //disallow directories\n    panel.canChooseDirectories = NO;\n    \n    //start in ~/Desktop\n    panel.directoryURL = [NSURL fileURLWithPath:[NSSearchPathForDirectoriesInDomains (NSDesktopDirectory, NSUserDomainMask, YES) firstObject]];\n    \n    //disable multiple selections\n    panel.allowsMultipleSelection = NO;\n    \n    //show it\n    response = [panel runModal];\n    if(NSModalResponseCancel == response)\n    {\n        //bail\n        goto bail;\n    }\n    \n    //load rules from specified file\n    data = [NSData dataWithContentsOfFile:panel.URL.path options:NSDataReadingMappedIfSafe | NSDataReadingUncached error:&error];\n    if(nil == data)\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: failed to load (imported) rules from %{public}@ (error: %{public}@)\", panel.URL.path, error);\n        goto bail;\n    }\n    \n    //deserialize\n    @try\n    {\n        //convert\n        importedRules = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];\n        if(nil == importedRules)\n        {\n            //error msg\n            os_log_error(logHandle, \"ERROR: failed to convert imported rules from JSON (error: %{public}@)\", error);\n            goto bail;\n        }\n    }\n    @catch(NSException* exception)\n    {\n        //bail\n        goto bail;\n    }\n    \n    //sanity check\n    if(YES != [importedRules isKindOfClass:[NSDictionary class]])\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: invalid format for imported rules (should be a dictionary, not a %{public}@)\", importedRules.className);\n        goto bail;\n    }\n    \n    //init\n    newRules = [NSMutableDictionary dictionary];\n    \n    //add each\n    for(NSString* key in importedRules)\n    {\n        //sanity check\n        if(YES != [importedRules[key] isKindOfClass:[NSArray class]])\n        {\n            //err msg\n            os_log_error(logHandle, \"ERROR: invalid format for imported rules (should be an array, not a %{public}@)\", [importedRules[key] className]);\n            goto bail;\n        }\n        \n        //create rule obj for each\n        for(NSDictionary* importedRule in importedRules[key])\n        {\n            //rule obj\n            Rule* rule = [[Rule alloc] initFromJSON:importedRule];\n           \n            //skip if invalid\n            if(nil == rule)\n            {\n                //err msg\n                os_log_error(logHandle, \"ERROR: invalid format for imported rule: %{public}@\", importedRule);\n                \n                //skip\n                continue;\n            }\n            \n            //found a non-user created rule\n            // means we're going to do a full import\n            if(userOnlyImport && ![rule isUserCreated]) {\n                userOnlyImport = NO;\n            }\n            \n            //inc\n            count++;\n            \n            //first rule\n            // init dictionary, array, etc...\n            if(nil == newRules[key])\n            {\n                //init\n                newRules[key] = [NSMutableDictionary dictionary];\n                newRules[key][KEY_RULES] = [NSMutableArray array];\n                \n                //add cs info\n                if(nil != rule.csInfo)\n                {\n                    //add\n                    newRules[key][KEY_CS_INFO] = rule.csInfo;\n                }\n            }\n            \n            //add rule obj\n            [newRules[key][KEY_RULES] addObject:rule];\n        }\n    }\n    \n    //archive rules\n    archivedRules = [NSKeyedArchiver archivedDataWithRootObject:newRules requiringSecureCoding:YES error:&error];\n    if(nil == archivedRules)\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: failed to archive rules: %{public}@\", error);\n    }\n    \n    //dbg msg\n    os_log_debug(logHandle, \"serialized (imported) rules\");\n    \n    //send to daemon\n    if(YES != [xpcDaemonClient importRules:archivedRules userOnly:userOnlyImport])\n    {\n        //bail\n        goto bail;\n    }\n    \n    //happy\n    imported = YES;\n    \n    //tell (any) windows rules changed\n    [[NSNotificationCenter defaultCenter] postNotificationName:RULES_CHANGED object:nil userInfo:nil];\n    \n    //show alert\n    showAlert(NSAlertStyleInformational, [NSString stringWithFormat:NSLocalizedString(@\"Imported %ld rules\",@\"Imported %ld rules\"), count], nil, @[NSLocalizedString(@\"OK\", @\"OK\")]);\n    \nbail:\n    \n    return imported;\n}\n\n//cleanup rules\n-(NSInteger)cleanupRules\n{\n    //result\n    NSInteger cleanedUp = -1;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"method '%s' invoked\", __PRETTY_FUNCTION__);\n    \n    //first show rules\n    [self showRules];\n    \n    //show alert\n    // if user cancels, just bail\n    if(NSAlertSecondButtonReturn == showAlert(NSAlertStyleInformational, NSLocalizedString(@\"Clean up rules referencing deleted, expired, or terminated items?\", @\"Clean up rules referencing deleted, expired, or terminated items?\"), nil, @[NSLocalizedString(@\"OK\",@\"OK\"), NSLocalizedString(@\"Cancel\",@\"Cancel\")]))\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"user cancelled rule cleanup\");\n        \n        //not an error though\n        cleanedUp = 0;\n        \n        //bail\n        goto bail;\n    }\n    \n    //call into daemon to cleanup\n    // returns number or deleted rules\n    cleanedUp = [xpcDaemonClient cleanupRules:YES];\n    if(cleanedUp < 0)\n    {\n        //bail\n        goto bail;\n    }\n    \n    //tell (any) windows rules changed\n    [[NSNotificationCenter defaultCenter] postNotificationName:RULES_CHANGED object:nil userInfo:nil];\n    \n    //share results w/ user\n    showAlert(NSAlertStyleInformational, [NSString stringWithFormat:NSLocalizedString(@\"Cleaned up %ld rules\",@\"Cleaned up %ld rules\"), cleanedUp], nil, @[NSLocalizedString(@\"OK\",@\"OK\")]);\n    \nbail:\n    \n    return cleanedUp;\n}\n\n@end\n"
  },
  {
    "path": "LuLu/App/RulesWindowController.h",
    "content": "//\n//  file: RulesWindowController.h\n//  project: lulu (main app)\n//  description: window controller for 'rules' table (header)\n//\n//  created by Patrick Wardle\n//  copyright (c) 2017 Objective-See. All rights reserved.\n//\n\n@import Cocoa;\n@import OSLog;\n\n#import \"Rule.h\"\n#import \"XPCDaemonClient.h\"\n#import \"AddRuleWindowController.h\"\n#import \"ItemPathsWindowController.h\"\n\n#import \"3rd-party/OrderedDictionary.h\"\n\n/* CONSTS */\n\n//id (tag) for detailed text in category table\n#define TABLE_ROW_NAME_TAG 100\n\n//id (tag) for detailed text\n#define TABLE_ROW_SUB_TEXT 101\n\n//id (tag) for delete button\n#define TABLE_ROW_SELECT_BTN_TAG 100\n#define TABLE_ROW_DELETE_BTN_TAG 101\n\n//show path(s)\n#define MENU_SHOW_PATHS 0\n\n//edit rule(s)\n#define MENU_EDIT_RULE 1\n\n//delete rule(s)\n#define MENU_DELETE_RULE 2\n\n\n/* INTERFACE */\n\n@interface RulesWindowController : NSWindowController <NSWindowDelegate, NSOutlineViewDataSource, NSOutlineViewDelegate, NSMenuDelegate>\n\n/* PROPERTIES */\n\n//(main) outline view\n@property (weak) IBOutlet NSOutlineView *outlineView;\n\n//observer for rules changed\n@property(nonatomic, retain)id rulesObserver;\n\n//loading rules overlay\n@property (weak) IBOutlet NSVisualEffectView* loadingRules;\n\n//loading rules spinner\n@property (weak) IBOutlet NSProgressIndicator* loadingRulesSpinner;\n\n//table items\n@property(nonatomic, retain)OrderedDictionary* rules;\n\n//rules view selector\n@property (weak) IBOutlet NSPopUpButton *rulesViewSelector;\n\n//table items\n// ...but filtered\n@property(nonatomic, retain)OrderedDictionary* rulesFiltered;\n\n//search box\n@property (weak) IBOutlet NSSearchField *filterBox;\n\n//top level view\n@property (weak) IBOutlet NSView *view;\n\n//window toolbar\n@property (weak) IBOutlet NSToolbar *toolbar;\n\n//selected index in rule view selector\n@property NSInteger selectedRuleView;\n\n//show item path(s) popup contoller\n@property(strong) ItemPathsWindowController *itemPathsWindowController;\n\n//panel for 'add rule'\n@property (weak) IBOutlet NSView *addRulePanel;\n\n//label for add rules button\n@property (weak) IBOutlet NSTextField *addRuleLabel;\n\n//button to add rules\n@property (weak) IBOutlet NSButton *addRuleButton;\n\n//add rules popup controller\n@property (strong) AddRuleWindowController *addRuleWindowController;\n\n//(last) added rule\n@property(nonatomic,retain)NSString* addedRule;\n\n//flag\n@property BOOL isAscending;\n\n/* METHODS */\n\n//configure (UI)\n-(void)configure;\n\n//add a rule\n-(IBAction)addRule:(id)sender;\n\n//delete a rule\n-(IBAction)deleteRule:(id)sender;\n\n@end\n"
  },
  {
    "path": "LuLu/App/RulesWindowController.m",
    "content": "//\n//  file: RulesWindowController.m\n//  project: lulu (main app)\n//  description: window controller for 'rules' table\n//\n//  created by Patrick Wardle\n//  copyright (c) 2017 Objective-See. All rights reserved.\n//\n\n#import \"consts.h\"\n#import \"RuleRow.h\"\n#import \"utilities.h\"\n#import \"AppDelegate.h\"\n#import \"XPCDaemonClient.h\"\n#import \"RulesWindowController.h\"\n#import \"AddRuleWindowController.h\"\n#import \"3rd-party/OrderedDictionary.h\"\n\n#define SORT_DESCRIPTOR_COLUMN_0 @\"sort_0\"\n\n/* GLOBALS */\n\n//log handle\nextern os_log_t logHandle;\n\n//xpc for daemon comms\nextern XPCDaemonClient* xpcDaemonClient;\n\n//custom view\n// to disable highlighting for disabled rules\n@interface CustomTableCellView : NSTableCellView\n@property (nonatomic) BOOL isDisabled;\n@end\n\n@implementation CustomTableCellView\n\n- (void)setBackgroundStyle:(NSBackgroundStyle)backgroundStyle {\n    [super setBackgroundStyle:backgroundStyle];\n    \n    //maintain disabled color even when selected\n    if (self.isDisabled) {\n        self.textField.textColor = NSColor.disabledControlTextColor;\n        [super setBackgroundStyle: NSBackgroundStyleLight];\n    }\n}\n\n@end\n\n@implementation RulesWindowController\n\n@synthesize rules;\n@synthesize toolbar;\n@synthesize addedRule;\n@synthesize filterBox;\n@synthesize addRulePanel;\n@synthesize loadingRules;\n@synthesize rulesFiltered;\n@synthesize rulesObserver;\n@synthesize loadingRulesSpinner;\n\n//init some settings\n-(void)awakeFromNib\n{\n    //set target\n    self.outlineView.target = self;\n    \n    //set 2x click handler\n    self.outlineView.doubleAction = @selector(doubleClickHandler:);\n    \n    return;\n}\n\n//configure (UI)\n-(void)configure\n{\n    //dbg msg\n    os_log_debug(logHandle, \"method '%s' invoked\", __PRETTY_FUNCTION__);\n\n    //set subtitle\n    [self setSubTitle];\n    \n    //first cleanup any expired/temp rules\n    [xpcDaemonClient cleanupRules:NO];\n    \n    //then load rules\n    [self loadRules:YES select:@0];\n\n    return;\n}\n\n//set subtitle to current profile\n-(void)setSubTitle\n{\n    //dbg msg\n    os_log_debug(logHandle, \"method '%s' invoked\", __PRETTY_FUNCTION__);\n    \n    //current profile\n    NSString* currentProfile = [xpcDaemonClient getCurrentProfile];\n    \n    //have profile?\n    if(0 != currentProfile.length) {\n        \n        //add subtitle\n        if (@available(macOS 11.0, *)) {\n            self.window.subtitle = [NSString stringWithFormat:NSLocalizedString(@\"Current Profile: %@\",@\"Current Profile: %@\"), currentProfile];\n        }\n    }\n    //set to default\n    else\n    {\n        //set\n        if (@available(macOS 11.0, *)) {\n            self.window.subtitle = NSLocalizedString(@\"Current Profile: Default\",@\"Current Profile: Default\");\n        }\n    }\n    \n    return;\n}\n\n//alloc/init\n// get rules and listen for new ones\n-(void)windowDidLoad\n{\n    //set default rule's view\n    self.selectedRuleView = RULE_TYPE_ALL;\n    \n    //set indentation level for outline view\n    self.outlineView.indentationPerLevel = 42;\n    \n    //pre-req for color of overlay\n    self.loadingRules.wantsLayer = YES;\n    \n    //round overlay's corners\n    self.loadingRules.layer.cornerRadius = 20.0;\n    \n    //mask overlay\n    self.loadingRules.layer.masksToBounds = YES;\n    \n    //set overlay's view material\n    self.loadingRules.material = NSVisualEffectMaterialHUDWindow;\n    \n    //set initial table header\n    self.outlineView.tableColumns.firstObject.headerCell.stringValue = NSLocalizedString(@\"All Rules\",@\"All Rules\");\n    \n    //set sort descriptor for first column\n    [self.outlineView.tableColumns[0] setSortDescriptorPrototype:[[NSSortDescriptor alloc] initWithKey:SORT_DESCRIPTOR_COLUMN_0 ascending:YES]];\n    \n    //set resizing\n    self.outlineView.columnAutoresizingStyle = NSTableViewFirstColumnOnlyAutoresizingStyle;\n    \n    //set it to whole too...\n    [self.outlineView setSortDescriptors:@[self.outlineView.tableColumns[0].sortDescriptorPrototype]];\n    \n    //set flag\n    self.isAscending = YES;\n \n    //setup observer for new rules\n    // will be broadcast (via XPC) when daemon updates rules\n    self.rulesObserver = [[NSNotificationCenter defaultCenter] addObserverForName:RULES_CHANGED object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notification)\n    {\n        //get new rules\n        [self loadRules:YES select:@(0)];\n    }];\n    \n    return;\n}\n\n//get rules from daemon\n// then, re-load rules table\n-(void)loadRules:(BOOL)showOverlay select:(NSNumber*)row\n{\n    //dbg msg\n    os_log_debug(logHandle, \"loading rules...\");\n    \n    //show overlay\n    if(YES == showOverlay)\n    {\n        //show overlay\n        self.loadingRules.hidden = NO;\n        \n        //start progress indicator\n        [self.loadingRulesSpinner startAnimation:nil];\n    }\n    \n    //in background get rules\n    // ...then load rule table table\n    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),\n    ^{\n        //current rules (from ext)\n        NSDictionary* currentRules = nil;\n        \n        //sorted keys\n        NSArray* sortedKeys = nil;\n        \n        //show overlay\n        if(YES == showOverlay)\n        {\n            //nap for UI (loading msg)\n            [NSThread sleepForTimeInterval:0.5f];\n        }\n        \n        //get rules\n        currentRules = [xpcDaemonClient getRules];\n        \n        //dbg msg\n        os_log_debug(logHandle, \"received %lu rules from daemon: %{public}@\", (unsigned long)currentRules.count, currentRules.allKeys);\n        \n        //sync rules\n        @synchronized (self)\n        {\n            //alloc\n            self.rules = [[OrderedDictionary alloc] init];\n        \n            //dbg msg\n            os_log_debug(logHandle, \"sorting rules...\");\n            \n            //sort by (rule) name\n            sortedKeys = [currentRules keysSortedByValueUsingComparator:^NSComparisonResult(id _Nonnull obj1, id  _Nonnull obj2)\n            {\n                //normal\n                if(YES == self.isAscending)\n                {\n                    //compare/return\n                    return [((Rule*)[((NSDictionary*)obj1)[KEY_RULES] firstObject]).name compare:((Rule*)[((NSDictionary*)obj2)[KEY_RULES] firstObject]).name options:NSCaseInsensitiveSearch];\n                }\n                //reversed\n                else\n                {\n                    //compare/return\n                    return [((Rule*)[((NSDictionary*)obj2)[KEY_RULES] firstObject]).name compare:((Rule*)[((NSDictionary*)obj1)[KEY_RULES] firstObject]).name options:NSCaseInsensitiveSearch];\n                }\n            }];\n            \n            //add sorted rules\n            for(NSInteger i = 0; i<sortedKeys.count; i++)\n            {\n                //add to ordered dictionary\n                [self.rules insertObject:currentRules[sortedKeys[i]] forKey:sortedKeys[i] atIndex:i];\n            }\n            \n        }//sync\n        \n        //show rules in UI\n        dispatch_async(dispatch_get_main_queue(), ^{\n            \n            //show overlay\n            if(YES == showOverlay)\n            {\n                //hide overlay\n                self.loadingRules.hidden = YES;\n            }\n            \n            //update ui\n            [self update:row];\n            \n            //set subtitle\n            [self setSubTitle];\n        });\n\n    });\n        \n    return;\n}\n\n//update outline view\n-(void)update:(NSNumber*)select\n{\n    //selected row\n    NSInteger selectedRow = -1;\n    \n    //sync\n    // filter & reload\n    @synchronized(self)\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"updating outline view for rules...\");\n        \n        //row to select\n        if(nil != select)\n        {\n            //set\n            selectedRow = select.intValue;\n        }\n        //get currently selected row\n        // default to first row if this fails\n        else\n        {\n            //get\n            selectedRow = self.outlineView.selectedRow;\n            if(-1 == selectedRow)\n            {\n                //default\n                selectedRow = 0;\n            }\n        }\n    \n        //always filter\n        self.rulesFiltered = [self filter];\n        \n        //begin updates\n        [self.outlineView beginUpdates];\n        \n        //full reload\n        [self.outlineView reloadData];\n        \n        //auto expand\n        [self.outlineView expandItem:nil expandChildren:YES];\n        \n        //end updates\n        [self.outlineView endUpdates];\n        \n        //find row for new rule\n        if(nil != self.addedRule)\n        {\n            //find row\n            selectedRow = [self findRowForItem:self.addedRule];\n            \n            //unset\n            self.addedRule = nil;\n        }\n    \n        //prev selected now beyond bounds?\n        // just default to select last row...\n        if(self.outlineView.numberOfRows > 0)\n        {\n            selectedRow = MIN(selectedRow, (self.outlineView.numberOfRows-1));\n        }\n        \n        //dbg msg\n        os_log_debug(logHandle, \"reselecting %ld\", (long)selectedRow);\n            \n        //reselect\n        [self.outlineView selectRowIndexes:[NSIndexSet indexSetWithIndex:selectedRow] byExtendingSelection:NO];\n            \n        //scroll\n        [self.outlineView scrollRowToVisible:selectedRow];\n\n    } //sync\n    \nbail:\n        \n    return;\n}\n\n//handler for rule select view\n-(IBAction)rulesViewSelectorHandler:(id)sender {\n    \n    //dbg msg\n    os_log_debug(logHandle, \"method '%s' invoked\", __PRETTY_FUNCTION__);\n    \n    //grab tag/save\n    self.selectedRuleView = self.rulesViewSelector.selectedItem.tag;\n    \n    //set column title\n    switch(self.selectedRuleView)\n    {\n        //all\n        case RULE_TYPE_ALL:\n            \n            self.outlineView.tableColumns.firstObject.headerCell.stringValue = NSLocalizedString(@\"All Rules\", @\"All Rules\");\n            break;\n            \n        //default\n        case RULE_TYPE_DEFAULT:\n            \n            self.outlineView.tableColumns.firstObject.headerCell.stringValue = NSLocalizedString(@\"Operating System Programs (required for system functionality)\", @\"Operating System Programs (required for system functionality)\");\n            break;\n            \n        //apple\n        case RULE_TYPE_APPLE:\n            \n            self.outlineView.tableColumns.firstObject.headerCell.stringValue = NSLocalizedString(@\"Apple Programs (automatically allowed & added here if 'allow apple programs' is set)\", @\"Apple Programs (automatically allowed & added here if 'allow apple programs' is set)\");\n            break;\n          \n        //baseline\n        case RULE_TYPE_BASELINE:\n            \n            self.outlineView.tableColumns.firstObject.headerCell.stringValue = NSLocalizedString(@\"Pre-installed 3rd-party Programs (automatically allowed & added here if 'allow installed applications' is set)\", @\"Pre-installed 3rd-party Programs (automatically allowed & added here if 'allow installed applications' is set)\");\n            break;\n            \n        //user\n        case RULE_TYPE_USER:\n            \n            self.outlineView.tableColumns.firstObject.headerCell.stringValue = NSLocalizedString(@\"User-specified Programs (manually added, or in response to an alert)\", @\"User-specified Programs (manually added, or in response to an alert)\");\n            \n            break;\n            \n        case RULE_TYPE_PASSIVE:\n            \n            self.outlineView.tableColumns.firstObject.headerCell.stringValue = NSLocalizedString(@\"Added passively (either if 'passive mode' is set, or no user was logged in when rule was created)\", @\"Added passively (either if 'passive mode' is set, or no user was logged in when rule was created)\");\n            \n            break;\n            \n        case RULE_TYPE_RECENT:\n            \n            self.outlineView.tableColumns.firstObject.headerCell.stringValue = NSLocalizedString(@\"Added in last 24 hours (sorted by creation time)\", @\"Added in last 24 hours (sorted by creation time)\");\n            break;\n            \n        \n        default:\n            break;\n    }\n    \n    //unselect (all) row\n    [self.outlineView deselectAll:nil];\n    \n    //reload table\n    [self update:@(0)];\n    \n    //'add rules' only allowed for 'all' and 'user' views\n    if( (self.selectedRuleView == RULE_TYPE_ALL) ||\n        (self.selectedRuleView == RULE_TYPE_USER) )\n    {\n        //change label color to default\n        self.addRuleLabel.textColor = [NSColor labelColor];\n        \n        //enable button\n        self.addRuleButton.enabled = YES;\n    }\n    //'add rule' not allowed for 'default'/'apple'/'baseline'\n    else\n    {\n        //change label color to gray\n        self.addRuleLabel.textColor = [NSColor controlBackgroundColor];\n        \n        //disable button\n        self.addRuleButton.enabled = NO;\n    }\n    \n    return;\n}\n\n//filter (search box) handler\n// just call into update method (which filters, etc)\n-(IBAction)filterBoxHandler:(id)sender {\n    \n    //dbg msg\n    os_log_debug(logHandle, \"filtering rules...\");\n    \n    //update\n    [self update:nil];\n    \n    return;\n}\n\n//double-click handler\n-(void)doubleClickHandler:(id)object\n{\n    NSInteger row = [self.outlineView clickedRow];\n    if (row < 0) return;\n\n    //get item\n    id item = [self.outlineView itemAtRow:row];\n\n    //only edit if it's a rule (not a group)\n    if ([item isKindOfClass:[NSArray class]]) {\n        return;\n    }\n\n    //grab rule\n    Rule *rule = (Rule *)item;\n\n    //dbg msg\n    os_log_debug(logHandle, \"editing rule %{public}@\", rule);\n\n    //edit (via add window)\n    [self addRule:rule];\n}\n\n\n//warn user the modifying default rules might break things\n-(NSModalResponse)showDefaultRuleAlert:(Rule*)rule action:(NSString*)action\n{\n    return showAlert(NSAlertStyleWarning, [NSString stringWithFormat:NSLocalizedString(@\"%@ is legitimate macOS process\", @\"%@ is legitimate macOS process\"), rule.name], [NSString stringWithFormat:NSLocalizedString(@\"%@ this rule, may impact legitimate system functionalty ...continue?\",@\"%@ this rule, may impact legitimate system functionalty ...continue?\"), action], @[NSLocalizedString(@\"Continue\", @\"Continue\"), NSLocalizedString(@\"Cancel\", @\"Cancel\")]);\n}\n\n//show paths in sheet\n-(void)showItemPaths:(NSString*)itemKey\n{\n    //current rules (from ext)\n    NSDictionary* currentRules = nil;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"method '%s' invoked with %{public}@\", __PRETTY_FUNCTION__, itemKey);\n    \n    //alloc sheet\n    self.itemPathsWindowController = [[ItemPathsWindowController alloc] initWithWindowNibName:@\"ItemPaths\"];\n\n    //get latest rules\n    currentRules = [xpcDaemonClient getRules];\n    \n    //set rules\n    self.itemPathsWindowController.item = currentRules[itemKey];\n    \n    //show it\n    [self.window beginSheet:self.itemPathsWindowController.window completionHandler:^(NSModalResponse returnCode) {\n        \n        //unset\n        self.itemPathsWindowController = nil;\n        \n    }];\n    \n    return;\n}\n\n//button handler for 'add rules'\n// show 'add rule' sheet and then, on close, add rule via XPC\n-(IBAction)addRule:(id)sender\n{\n    //dbg msg\n    os_log_debug(logHandle, \"method '%s' invoked with %{public}@\", __PRETTY_FUNCTION__, sender);\n    \n    //alloc sheet\n    self.addRuleWindowController = [[AddRuleWindowController alloc] initWithWindowNibName:@\"AddRule\"];\n    \n    //invoked with existing rule (to edit)\n    if(YES == [sender isKindOfClass:[Rule class]])\n    {\n        //default rule?\n        //show alert/warning\n        if(RULE_TYPE_DEFAULT == ((Rule*)sender).type.intValue)\n        {\n            //show alert\n            // ...and bail if user cancels\n            if(NSAlertSecondButtonReturn == [self showDefaultRuleAlert:sender action:@\"Editing\"])\n            {\n                //bail\n                goto bail;\n            }\n        }\n        \n        //set rule\n        self.addRuleWindowController.rule = (Rule*)sender;\n    }\n    \n    //show it\n    // on close/OK, invoke XPC to add rule, then reload\n    NSModalResponse response = [NSApp runModalForWindow:self.addRuleWindowController.window];\n    {\n        \n        //(existing) rule\n        Rule* rule = nil;\n        \n        //dbg msg\n        os_log_debug(logHandle, \"add/edit rule window closed...\");\n        \n        //on OK, add rule via XPC\n        if(response == NSModalResponseOK)\n        {\n            //was an update to an existing rule?\n            // delete it first, then go ahead and add\n            if(nil != (rule = self.addRuleWindowController.rule))\n            {\n                //remove rule via XPC\n                [xpcDaemonClient deleteRule:rule.key rule:rule.uuid];\n            }\n            \n            //add rule via XPC\n            [xpcDaemonClient addRule:self.addRuleWindowController.info];\n            \n            //new rule?\n            // save path, and toggle to user tab\n            if(nil == rule)\n            {\n                //save into iVar\n                // allows table to select/scroll to this new rule\n                self.addedRule = self.addRuleWindowController.info[KEY_PATH];\n            }\n            \n            //reload\n            [self loadRules:YES select:nil];\n        }\n        \n        //unset add rule window controller\n        self.addRuleWindowController = nil;\n        \n    }\n    \nbail:\n    \n    return;\n}\n\n//init array of filtered rules\n// determines what rule view is selected, then sort based on that and also what's in search box\n-(OrderedDictionary*)filter\n{\n    //filtered items\n    OrderedDictionary* results = nil;\n    \n    //sorted keys\n    NSArray* sortedKeys = nil;\n    \n    //sorted rules\n    OrderedDictionary* sortedRules = nil;\n    \n    //filter string\n    NSString* filter = nil;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"filtering rules...\");\n    \n    //init\n    results = [[OrderedDictionary alloc] init];\n    \n    //grab filter string\n    filter = self.filterBox.stringValue;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"selected rule view: %ld\", self.selectedRuleView);\n    \n    //all/no filter\n    // don't need to filter\n    if( (RULE_TYPE_ALL == self.selectedRuleView) &&\n        (0 == filter.length) )\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"selected toolbar item is 'all' and filter box is empty ...no need to filter\");\n        \n        //no filter\n        results = self.rules;\n        \n        //bail\n        goto bail;\n    }\n    \n    //dbg msg\n    if(0 != filter.length)\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"filtering on '%{public}@'\", filter);\n    }\n        \n    //scan all rules\n    // add any that match rule view and filter string\n    {[self.rules enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL* stop) {\n        \n        //item\n        // cs info, rules, etc\n        NSMutableDictionary* item = nil;\n        \n        //item's rules\n        NSArray* itemRules = nil;\n        \n        //(item') recent rules\n        NSMutableArray* recentRules = nil;\n        \n        //(item's) rules that match\n        NSMutableArray* matchedRules = nil;\n        \n        //make copy\n        item = [value mutableCopy];\n        \n        //item's rules\n        itemRules = item[KEY_RULES];\n        \n        //init\n        matchedRules = [NSMutableArray array];\n        \n        //not on 'all'/'recent' view?\n        // skip rules if they don't match selected toolbar type\n        if( (RULE_TYPE_ALL != self.selectedRuleView) &&\n            (RULE_TYPE_RECENT != self.selectedRuleView) )\n        {\n            //check all item's rule for match\n            for(Rule* itemRule in itemRules)\n            {\n                //match?\n                if(self.selectedRuleView == itemRule.type.intValue)\n                {\n                    //add\n                    [matchedRules addObject:itemRule];\n                }\n            }\n            \n            //done if no item rules match\n            if(0 == matchedRules.count)\n            {\n                return;\n            }\n            \n            //update\n            item[KEY_RULES] = [matchedRules mutableCopy];\n            \n            //reset\n            // as we reuse this in filtering\n            [matchedRules removeAllObjects];\n        }\n        \n        //recent?\n        if(RULE_TYPE_RECENT == self.selectedRuleView)\n        {\n            //get (item's) recent rules\n            recentRules = [self recentRules:itemRules];\n            \n            //item doesn't have any recent rules\n            if(0 == recentRules.count)\n            {\n                //skip\n                return;\n            }\n            \n            //make copy\n            item = [value mutableCopy];\n            \n            //update item's rules\n            item[KEY_RULES] = recentRules;\n        }\n        \n        //no filter?\n        // we're done\n        if(0 == filter.length)\n        {\n            //append\n            [results insertObject:item forKey:key atIndex:results.count];\n                        \n            //next\n            return;\n        }\n        \n        /* NOW FILTER */\n        \n        //check each rule(s) on filter string\n        for(Rule* rule in item[KEY_RULES])\n        {\n            //match?\n            // save rule\n            if(YES == [rule matchesString:filter])\n            {\n                //add\n                [matchedRules addObject:rule];\n            }\n        }\n        \n        //any matched (item) rules?\n        // update item rule array and add item\n        if(0 != matchedRules.count)\n        {\n            //update item's rules\n            item[KEY_RULES] = matchedRules;\n            \n            //append to filtered results\n            [results insertObject:item forKey:key atIndex:results.count];\n        }\n        \n    }];}\n    \n    //sort recent rules\n    if(RULE_TYPE_RECENT == self.selectedRuleView)\n    {\n        //nap for UI (loading msg)\n        [NSThread sleepForTimeInterval:0.5f];\n        \n        //dbg msg\n        os_log_debug(logHandle, \"sorting (recent) rules by creation timestamp...\");\n        \n        //init\n        sortedRules = [[OrderedDictionary alloc] init];\n        \n        //sort by (rule) timestamp\n        sortedKeys = [results keysSortedByValueUsingComparator:^NSComparisonResult(id _Nonnull obj1, id  _Nonnull obj2)\n        {\n            //normal\n            if(YES == self.isAscending)\n            {\n                //compare/return\n                return [((Rule*)[((NSDictionary*)obj2)[KEY_RULES] firstObject]).creation compare:((Rule*)[((NSDictionary*)obj1)[KEY_RULES] firstObject]).creation];\n            }\n            //reversed\n            else\n            {\n                //compare/return\n                return [((Rule*)[((NSDictionary*)obj1)[KEY_RULES] firstObject]).creation compare:((Rule*)[((NSDictionary*)obj2)[KEY_RULES] firstObject]).creation];\n            }\n        }];\n        \n        //add sorted rules\n        for(NSInteger i = 0; i<sortedKeys.count; i++)\n        {\n            //add to ordered dictionary\n            [sortedRules insertObject:results[sortedKeys[i]] forKey:sortedKeys[i] atIndex:i];\n        }\n        \n        results = sortedRules;\n    }\n            \nbail:\n    \n    //dbg msg\n    os_log_debug(logHandle, \"filtered rules: %{public}@\", results.allKeys);\n    \n    return results;\n}\n\n//item's recent rules\n// any that are after boot time\n-(NSMutableArray*)recentRules:(NSArray*)itemRules\n{\n    //24 hrs ago\n    NSDate* cutoff = nil;\n    \n    //recent\n    NSMutableArray* recentRules = nil;\n    \n    //alloc/init\n    recentRules = [NSMutableArray array];\n    \n    //init\n    cutoff = [[NSDate date] dateByAddingTimeInterval:-(24 * 60 * 60)];\n    \n    //check each rule(s)\n    for(Rule* rule in itemRules)\n    {\n        //skip older rules\n        // ...didn't have creation time\n        if(nil == rule.creation)\n        {\n            continue;\n        }\n        \n        //not after\n        if(NSOrderedDescending != [rule.creation compare:cutoff])\n        {\n            continue;\n        }\n\n        //add\n        [recentRules addObject:rule];\n    }\n    \nbail:\n    \n    //sort: ascending\n    if(YES == self.isAscending)\n    {\n        //sort from newest to oldest\n        [recentRules sortUsingComparator:^NSComparisonResult(Rule *rule1, Rule *rule2) {\n                //compare the creation dates\n                return [rule2.creation compare:rule1.creation];\n        }];\n    }\n    //sort: descending\n    else\n    {\n        //sort from oldest to newest\n        [recentRules sortUsingComparator:^NSComparisonResult(Rule *rule1, Rule *rule2) {\n                //compare the creation dates\n                return [rule1.creation compare:rule2.creation];\n        }];\n    }\n    \n    return recentRules;\n}\n\n#pragma mark -\n#pragma mark outline delegate methods\n\nstatic const NSUInteger kDeleteKeyCode = 51;\n\n//handle delete\n// alert and delete rule\n- (void)keyDown:(NSEvent *)event {\n    \n    // Only care about delete key\n    if (event.keyCode != kDeleteKeyCode) {\n        [super keyDown:event];\n        return;\n    }\n        \n    NSInteger selectedRow = self.outlineView.selectedRow;\n    if (selectedRow == -1) {\n        [super keyDown:event];\n        return;\n    }\n        \n    //show alert\n    NSModalResponse response = showAlert(NSAlertStyleWarning,\n                                           NSLocalizedString(@\"Delete Rule?\", @\"Delete Rule?\"),\n                                           nil,\n                                           @[NSLocalizedString(@\"Delete\", @\"Delete\"),\n                                             NSLocalizedString(@\"Cancel\", @\"Cancel\")]);\n        \n    //user chose delete\n    if (response == NSAlertFirstButtonReturn) {\n        \n            //delete rule needs menu item\n            NSMenuItem *tempMenuItem = [[NSMenuItem alloc] init];\n            tempMenuItem.representedObject = @(selectedRow);\n        \n            //delete rule\n            [self deleteRule:tempMenuItem];\n    }\n    \n    return;\n\n}\n\n//number of the children\n-(NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item\n{\n    //# of children\n    // root: all\n    // non-root, just items in item\n    return (nil == item) ? self.rulesFiltered.count : [item count];\n}\n\n//items (processes) are expandable\n// these items are built from items of type array\n-(BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item\n{\n    return (YES == [item isKindOfClass:[NSArray class]]);\n}\n\n//return child\n-(id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item\n{\n    //child\n    id child = nil;\n    \n    //key\n    id key = nil;\n    \n    //a root item?\n    // 'child' is array of rules\n    if(nil == item)\n    {\n        //key\n        key = [self.rulesFiltered keyAtIndex:index];\n        \n        //child\n        child = self.rulesFiltered[key][KEY_RULES];\n    }\n    //otherwise\n    // child is rule at index\n    else\n    {\n        //set child\n        child = item[index];\n    }\n    \n    return child;\n}\n\n//return custom row for view\n// allows highlighting, etc...\n-(NSTableRowView *)outlineView:(NSOutlineView *)outlineView rowViewForItem:(id)item\n{\n    //row view\n    RuleRow* rowView = nil;\n    \n    //row ID\n    static NSString* const kRowIdentifier = @\"RowView\";\n    \n    //try grab existing row view\n    rowView = [self.outlineView makeViewWithIdentifier:kRowIdentifier owner:self];\n    \n    //make new if needed\n    if(nil == rowView)\n    {\n        //create new\n        // size doesn't matter\n        rowView = [[RuleRow alloc] initWithFrame:NSZeroRect];\n        \n        //set row ID\n        rowView.identifier = kRowIdentifier;\n    }\n    \n    return rowView;\n}\n\n//table delegate method\n// return new cell for row\n-(NSView *)outlineView:(NSOutlineView *)outlineView viewForTableColumn:(NSTableColumn *)tableColumn item:(id)item\n{\n    //date formatter\n    NSDateFormatter *dateFormatter = nil;\n    \n    //view\n    NSTableCellView* cell = nil;\n    \n    //first rule\n    Rule* rule = nil;\n    \n    //first column\n    // process or connection\n    if(tableColumn == self.outlineView.tableColumns[0])\n    {\n        //a root item?\n        if(YES == [item isKindOfClass:[NSArray class]])\n        {\n            //grab first rule\n            rule = [item firstObject];\n\n            //create/configure process cell\n            cell = [self createProcessCell:rule];\n        }\n        //child\n        // create/configure event cell\n        else\n        {\n            //create/configure process cell\n            cell = [self createConnectionCell:item];\n        }\n    }\n    //all other columns\n    // init a basic cell\n    else if(tableColumn == self.outlineView.tableColumns[1])\n    {\n        //cell\n        cell = [self.outlineView makeViewWithIdentifier:@\"ruleCell\" owner:self];\n        if(nil == cell) goto bail;\n                \n        //only add rule for connection (i.e. not item)\n        if(YES == [item isKindOfClass:[Rule class]])\n        {\n            //action\n            NSString* action = nil;\n            \n            //typecast\n            rule = (Rule*)item;\n            \n            //block?\n            if(RULE_STATE_BLOCK == rule.action.integerValue)\n            {\n                //set image\n                cell.imageView.image = [NSImage imageNamed:@\"RulesBlock\"];\n                \n                //duration: process\n                if(nil != rule.pid)\n                {\n                    //set msg\n                    action = [NSString stringWithFormat:NSLocalizedString(@\"Block (pid: %@)\", @\"Block (pid: %@)\"), rule.pid];\n                }\n                \n                //duration: expiration\n                else if(nil != rule.expiration)\n                {\n                    //init date formatter\n                    dateFormatter = [[NSDateFormatter alloc] init];\n                    [dateFormatter setDateStyle:NSDateFormatterNoStyle];\n                    [dateFormatter setTimeStyle:NSDateFormatterShortStyle];\n                    \n                    //set msg\n                    action = [NSString stringWithFormat:NSLocalizedString(@\"Block (until: %@)\", @\"Block (until: %@)\"), [dateFormatter stringFromDate:rule.expiration]];\n                }\n                \n                //normal\n                else\n                {\n                    //set action text\n                    action = NSLocalizedString(@\"Block\", @\"Block\");\n                }\n                \n            }\n            //allow?\n            else\n            {\n                //set image\n                cell.imageView.image = [NSImage imageNamed:@\"RulesAllow\"];\n                \n                //duration: process\n                if(nil != rule.pid)\n                {\n                    //set msg\n                    action = [NSString stringWithFormat:NSLocalizedString(@\"Allow (pid: %@)\", @\"Allow (pid: %@)\"), rule.pid];\n                }\n                \n                //duration: expiration\n                else if(nil != rule.expiration)\n                {\n                    //init date formatter\n                    dateFormatter = [[NSDateFormatter alloc] init];\n                    [dateFormatter setDateStyle:NSDateFormatterNoStyle];\n                    [dateFormatter setTimeStyle:NSDateFormatterShortStyle];\n                    \n                    //set msg\n                    action = [NSString stringWithFormat:NSLocalizedString(@\"Allow (until: %@)\", @\"Allow (until: %@)\"), [dateFormatter stringFromDate:rule.expiration]];\n                }\n                \n                //normal\n                else\n                {\n                    //set action text\n                    action = NSLocalizedString(@\"Allow\", @\"Allow\");\n                }\n            }\n            \n            //disabled?\n            // set flag (for highlighting) and color\n            ((CustomTableCellView *)cell).isDisabled = rule.isDisabled.boolValue;\n            if (rule.isDisabled.boolValue) {\n                cell.textField.textColor = NSColor.disabledControlTextColor;\n            } else {\n                cell.textField.textColor = NSColor.controlTextColor;\n            }\n        \n            //set text\n            cell.textField.stringValue = action;\n        }\n        //otherwise unset image/text\n        else\n        {\n            //grab first rule\n            rule = [item firstObject];\n            \n            //unset image\n            cell.imageView.image = nil;\n            \n            //unset text\n            cell.textField.stringValue = @\"\";\n        }\n    }\n    \nbail:\n    \n    return cell;\n}\n\n//sort\n// really for now, just reverse\n-(void)outlineView:(NSOutlineView *)outlineView sortDescriptorsDidChange:(NSArray<NSSortDescriptor *> *)oldDescriptors\n{\n    //dbg msg\n    os_log_debug(logHandle, \"method '%s' invoked\", __PRETTY_FUNCTION__);\n    \n    //only sort first column: rule name\n    if(YES == [outlineView.sortDescriptors.firstObject.key isEqualToString:SORT_DESCRIPTOR_COLUMN_0])\n    {\n        //reverse\n        [self.rules reverse];\n        \n        //toggle\n        self.isAscending = !self.isAscending;\n        \n        //unselect row\n        // want top row to be selected after reverse\n        [self.outlineView deselectAll:nil];\n\n        //refresh table\n        [self update:nil];\n    }\n    \n    return;\n}\n\n//create & customize process cell\n// these are the root cells, that hold the item (process)\n-(NSTableCellView*)createProcessCell:(Rule*)rule\n{\n    //item cell\n    NSTableCellView* processCell = nil;\n    \n    //directory\n    NSString* directory = nil;\n    \n    //create cell\n    processCell = [self.outlineView makeViewWithIdentifier:@\"processCell\" owner:self];\n    \n    //global rule?\n    // no icon, no path, etc.\n    if(YES == rule.isGlobal.boolValue)\n    {\n        //set icon\n        processCell.imageView.image = [[NSWorkspace sharedWorkspace]\n        iconForFileType: NSFileTypeForHFSTypeCode(kGenericHardDiskIcon)];\n        \n        //set text\n        processCell.textField.stringValue = NSLocalizedString(@\"Any program\", @\"Any program\");\n        \n        //(un)set detailed text\n        ((NSTextField*)[processCell viewWithTag:TABLE_ROW_SUB_TEXT]).stringValue = @\"\";\n    }\n    //directory rule?\n    else if(YES == rule.isDirectory.boolValue)\n    {\n        //init directory\n        // ...by removing *\n        directory = [rule.path substringToIndex:(rule.path.length-1)];\n        \n        //set icon\n        processCell.imageView.image = getIconForProcess(directory);\n        \n        //main text\n        // last directory\n        processCell.textField.stringValue = [NSString stringWithFormat:NSLocalizedString(@\"Programs within \\\"%@/\\\"\", @\"Programs within \\\"%@/\\\"\"), directory.lastPathComponent];\n        \n        //details\n        // just use path\n        ((NSTextField*)[processCell viewWithTag:TABLE_ROW_SUB_TEXT]).stringValue = rule.path;\n    }\n    \n    //non global rule?\n    // set icon, path, etc.\n    else\n    {\n        //set icon\n        processCell.imageView.image = getIconForProcess(rule.path);\n\n        //main text\n        // item's name\n        processCell.textField.stringValue = rule.name;\n        \n        //format/set details\n        ((NSTextField*)[processCell viewWithTag:TABLE_ROW_SUB_TEXT]).stringValue = [self formatItemDetails:rule];\n    }\n    \n    return processCell;\n}\n\n//format details for item\n-(NSString*)formatItemDetails:(Rule*)rule\n{\n    //details\n    NSString* details = @\"\";\n        \n    //cs info?\n    if(nil != rule.csInfo)\n    {\n        //format, based on signer\n        switch([rule.csInfo[KEY_CS_SIGNER] intValue])\n        {\n            //apple\n            case Apple:\n                details = [NSString stringWithFormat:NSLocalizedString(@\"%@ (signer: Apple Proper)\", @\"%@ (signer: Apple Proper)\"), rule.csInfo[KEY_CS_ID]];\n                break;\n            \n            //app store\n            case AppStore:\n                details = [NSString stringWithFormat:NSLocalizedString(@\"%@ (signer: Apple Mac OS App Store)\", @\"%@ (signer: Apple Mac OS App Store)\"), rule.csInfo[KEY_CS_ID]];\n                break;\n                \n            //dev id\n            case DevID:\n                details = [NSString stringWithFormat:NSLocalizedString(@\"%@ (signer: %@)\",@\"%@ (signer: %@)\"), rule.csInfo[KEY_CS_ID], [rule.csInfo[KEY_CS_AUTHS] firstObject]];\n                break;\n                \n            //ad hoc\n            case AdHoc:\n                details = [NSString stringWithFormat:NSLocalizedString(@\"%@ (signer: %@)\", @\"%@ (signer: %@)\"), rule.csInfo[KEY_CS_ID], NSLocalizedString(@\"Ad hoc\", @\"Ad hoc\")];\n                break;\n                \n            default:\n                break;\n        }\n    }\n    \n    //no valid cs info\n    // just use path / and mention issue\n    if(0 == details.length)\n    {\n        //set\n        details = [NSString stringWithFormat:NSLocalizedString(@\"%@ (signer: invalid/unsigned)\", @\"%@ (signer: invalid/unsigned)\"), rule.path];\n    }\n\n    return details;\n}\n\n//create & customize connection cell\n-(NSTableCellView*)createConnectionCell:(Rule*)rule\n{\n    //endpoint port\n    NSString* port = nil;\n    \n    //endpoint addr\n    NSString* address = nil;\n    \n    //item cell\n    //NSTableCellView* cell = nil;\n    \n    //contents\n    NSMutableString* contents = nil;\n    \n    //time stamp\n    NSString* timestamp = nil;\n    \n    //date formatter\n    static NSDateFormatter *dateFormatter = nil;\n    \n    //cell\n    CustomTableCellView *cell = (CustomTableCellView *)[self.outlineView makeViewWithIdentifier:@\"simpleCell\" owner:self];\n    \n    //disabled?\n    // set flag (for highlighting) and color\n    cell.isDisabled = rule.isDisabled.boolValue;\n    if (rule.isDisabled.boolValue) {\n        cell.textField.textColor = NSColor.disabledControlTextColor;\n    } else {\n        cell.textField.textColor = NSColor.controlTextColor;\n    }\n    \n    //reset text\n    ((NSTableCellView*)cell).textField.stringValue = @\"\";\n    ((NSTableCellView*)cell).textField.attributedStringValue = [[NSAttributedString alloc] initWithString:@\"\"];\n    \n    //set endpoint addr\n    address = (YES == [rule.endpointAddr isEqualToString:VALUE_ANY]) ? NSLocalizedString(@\"any address\",@\"any address\") : rule.endpointAddr;\n    \n    //set endpoint port\n    port = (YES == [rule.endpointPort isEqualToString:VALUE_ANY]) ? NSLocalizedString(@\"any port\",@\"any port\") : rule.endpointPort;\n    \n    //default contents\n    // address: port\n    contents = [NSMutableString stringWithFormat:@\"%@:%@\", address, port];\n    \n    //in \"recents\" view, add creation timestamp\n    if(RULE_TYPE_RECENT == self.selectedRuleView)\n    {\n        //init\n        dateFormatter = [[NSDateFormatter alloc] init];\n        \n        //config\n        [dateFormatter setDateFormat:@\"yyyy-MM-dd HH:mm\"];\n        \n        //init (formatted) timestamp\n        timestamp = [NSString stringWithFormat:@\" (created at: %@)\", [dateFormatter stringFromDate:rule.creation]];\n        \n        //append\n        [contents appendString:timestamp];\n    }\n\n    //set text\n    cell.textField.stringValue = contents;\n    \n    return cell;\n}\n\n//menu when user 2x clicks, or clicks on rule menu\n-(IBAction)showRuleMenu:(NSButton*)sender\n{\n    BOOL mixedStates = NO;\n    \n    NSString* editTitle = nil;\n    NSString* enableTitle = nil;\n    NSString* deleteTitle = nil;\n    NSString* disableTitle = nil;\n    NSString* showPathsTitle = nil;\n    \n    NSInteger row = 0;\n    row = [self.outlineView rowForView:sender];\n    if (row < 0) return;\n    \n    //get item\n    id item = [self.outlineView itemAtRow:row];\n    \n    //set flag\n    BOOL isGroup = [item isKindOfClass:[NSArray class]];\n    \n    //determine if there are mixed states?\n    if(isGroup && [item count] > 1) {\n        \n        BOOL firstState = ((Rule*)[item firstObject]).isDisabled.boolValue;\n        for(int i = 1; i < [item count] && !mixedStates; i++) {\n            mixedStates = (((Rule*)item[i]).isDisabled.boolValue != firstState);\n        }\n    }\n    \n    //set rule\n    Rule* rule = isGroup ? [item firstObject] : (Rule *)item;\n   \n    //set base\n    NSString* base = NSLocalizedString(@\"Rule\", nil);\n    if(isGroup && [item count] > 1) {\n        base = NSLocalizedString(@\"Rules\", nil);\n    }\n    \n    //set titles\n    editTitle = [NSString stringWithFormat:NSLocalizedString(@\"Edit %@\", @\"Edit %@\"), base];\n    deleteTitle = [NSString stringWithFormat:NSLocalizedString(@\"Delete %@\", @\"Delete %@\"), base];\n\n    enableTitle = [NSString stringWithFormat:NSLocalizedString(@\"Enable %@\", @\"Enable %@\"), base];\n    disableTitle = [NSString stringWithFormat:NSLocalizedString(@\"Disable %@\", @\"Disable %@\"), base];\n    \n    //dbg msg\n    os_log_debug(logHandle, \"row: %ld, item: %{public}@\", (long)row, item);\n\n    //alloc menu\n    NSMenu *menu = [[NSMenu alloc] initWithTitle:@\"Rule Menu\"];\n    menu.autoenablesItems = NO;\n    \n    //start with edit\n    // but only for rules (not group)\n    if(!isGroup) {\n        [menu addItem:[self createMenuItemWithTitle:editTitle action:@selector(editRule:) row:row]];\n    }\n\n    //mixed states (in groups)\n    // add both enable and disable\n    if(mixedStates) {\n        [menu addItem:[self createMenuItemWithTitle:enableTitle action:@selector(enableRule:) row:row]];\n        [menu addItem:[self createMenuItemWithTitle:disableTitle action:@selector(disableRule:) row:row]];\n    }\n    \n    //not mixed or single rule\n    // so can just add one option to toggle\n    else\n    {\n        //rule disabled?\n        // set 'enable' option\n        if(rule.isDisabled.boolValue) {\n            [menu addItem:[self createMenuItemWithTitle:enableTitle action:@selector(enableRule:) row:row]];\n        }\n        \n        //rule enabled?\n        // set 'disable' option\n        else {\n            [menu addItem:[self createMenuItemWithTitle:disableTitle action:@selector(disableRule:) row:row]];\n        }\n    }\n    \n    //separator\n    [menu addItem:[NSMenuItem separatorItem]];\n    \n    //add delete\n    [menu addItem:[self createMenuItemWithTitle:deleteTitle action:@selector(deleteRule:) row:row]];\n    \n    //separator\n    [menu addItem:[NSMenuItem separatorItem]];\n\n    //add show paths\n    showPathsTitle = NSLocalizedString(@\"Display Path(s)\", nil);\n    [menu addItem:[self createMenuItemWithTitle:showPathsTitle action:@selector(showPaths:) row:row]];\n    \n    //show menu below button\n    NSPoint pt = NSMakePoint(NSMinX(sender.bounds), NSMaxY(sender.bounds));\n    [menu popUpMenuPositioningItem:nil atLocation:pt inView:sender];\n\n    return;\n}\n\n//create menu item with title\n-(NSMenuItem*)createMenuItemWithTitle:(NSString*)title action:(SEL)action row:(NSInteger)row {\n    NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:title action:action keyEquivalent:@\"\"];\n    item.target = self;\n    item.representedObject = @(row);\n    return item;\n}\n\n//edit rule\n// just show 'add rule' window with pre-filled data\n-(void)editRule:(NSMenuItem*)sender\n{\n    //grab rule\n    // note: edit is only shown for rules (not item group)\n    Rule *rule = [self.outlineView itemAtRow:[sender.representedObject integerValue]];\n    \n    //dbg msg\n    os_log_debug(logHandle, \"editing rule %{public}@\", rule);\n    \n    //edit (via add window)\n    [self addRule:rule];\n    \n    return;\n}\n\n//enable rule(s) via XPC\n-(void)enableRule:(NSMenuItem*)sender\n{\n    Rule *rule = nil;\n    NSString* uuid = nil;\n    NSInteger selectedRow = -1;\n    \n    NSInteger row = [sender.representedObject integerValue];\n    \n    id item = [self.outlineView itemAtRow:row];\n    \n    if([item isKindOfClass:[NSArray class]]) {\n        rule = [item firstObject];\n    } else {\n        rule = item;\n        uuid = rule.uuid;\n    }\n    \n    //save selected row\n    selectedRow = self.outlineView.selectedRow;\n    if(-1 == selectedRow) {\n        selectedRow = row;\n    }\n    \n    //dbg msg\n    os_log_debug(logHandle, \"enabling rule %{public}@\", rule);\n    \n    //enable rule via XPC\n    // nil uuid, means toggle all rules for item (process)\n    [xpcDaemonClient toggleRule:rule.key rule:uuid state:@RULE_TOGGLE_STATE_ENABLE];\n    \n    //refresh\n    [self loadRules:NO select:@(selectedRow)];\n    \n    return;\n}\n\n//disable rule(s) via XPC\n-(void)disableRule:(NSMenuItem*)sender\n{\n    Rule *rule = nil;\n    NSString* uuid = nil;\n    NSInteger selectedRow = -1;\n    \n    NSInteger row = [sender.representedObject integerValue];\n    \n    id item = [self.outlineView itemAtRow:row];\n    \n    if([item isKindOfClass:[NSArray class]]) {\n        rule = [item firstObject];\n    } else {\n        rule = item;\n        uuid = rule.uuid;\n    }\n    \n    //save selected row\n    selectedRow = self.outlineView.selectedRow;\n    if(-1 == selectedRow) {\n        selectedRow = row;\n    }\n    \n    //dbg msg\n    os_log_debug(logHandle, \"disabling rule %{public}@\", rule);\n    \n    //disable rule via XPC\n    // nil uuid, means toggle all rules for item (process)\n    [xpcDaemonClient toggleRule:rule.key rule:uuid state:@RULE_TOGGLE_STATE_DISABLE];\n    \n    //refresh\n    [self loadRules:NO select:@(selectedRow)];\n    \n    return;\n}\n\n\n//delete rule(s) via XPC\n-(void)deleteRule:(NSMenuItem *)sender\n{\n    Rule *rule = nil;\n    NSString* uuid = nil;\n    \n    NSInteger row = [sender.representedObject integerValue];\n    \n    id item = [self.outlineView itemAtRow:row];\n    \n    if([item isKindOfClass:[NSArray class]]) {\n        rule = [item firstObject];\n    } else {\n        rule = item;\n        uuid = rule.uuid;\n    }\n    \n    //default rule?\n    // show alert/warning\n    if(RULE_TYPE_DEFAULT == rule.type.intValue)\n    {\n        //show alert\n        // ...and bail if user cancels\n        if(NSAlertSecondButtonReturn == [self showDefaultRuleAlert:rule action:@\"Deleting\"])\n        {\n            //bail\n            goto bail;\n        }\n    }\n    \n    //dbg msg\n    os_log_debug(logHandle, \"deleting rule key: %{public}@, rule uuid: %{public}@\", rule.key, uuid);\n    \n    //remove rule via XPC\n    // nil uuid, means delete all rules for item (process)\n    [xpcDaemonClient deleteRule:rule.key rule:uuid];\n    \n    //refresh\n    [self loadRules:NO select:@(row)];\n    \nbail:\n    \n    return;\n}\n\n//show paths\n-(void)showPaths:(NSMenuItem *)sender\n{\n    Rule *rule = nil;\n    NSInteger row = [sender.representedObject integerValue];\n    \n    id item = [self.outlineView itemAtRow:row];\n    \n    if([item isKindOfClass:[NSArray class]]) {\n        rule = [item firstObject];\n    } else {\n        rule = item;\n    }\n    \n    [self showItemPaths:rule.key];\n    \n    return;\n}\n\n//find row for item\n-(NSInteger)findRowForItem:(id)item\n{\n    //row\n    NSInteger row = -1;\n    \n    //current item\n    id currentItem = nil;\n    \n    //scan outline to find matching object\n    for(NSUInteger i = 0; i < self.outlineView.numberOfRows; i++)\n    {\n        //extract current item\n        currentItem = [self.outlineView itemAtRow:i];\n        \n        //looking for path?\n        // only apply to item/process objects\n        if( (YES == [item isKindOfClass:[NSString class]]) &&\n            (YES == [currentItem isKindOfClass:[NSArray class]]) )\n        {\n            //paths match?\n            if(YES == [item isEqualToString:((Rule*)[currentItem firstObject]).path])\n            {\n               //save index\n               row = i;\n               \n               //all done\n               break;\n            }\n        }\n        \n        //looking for item?\n        // grab first rule from it's array and compare paths\n        else if( (YES == [item isKindOfClass:[NSArray class]]) &&\n                 (YES == [currentItem isKindOfClass:[NSArray class]]) )\n        {\n            //paths match?\n            if(YES == [((Rule*)[item firstObject]).path isEqualToString:((Rule*)[currentItem firstObject]).path])\n            {\n               //save index\n               row = i;\n               \n               //all done\n               break;\n            }\n        }\n        \n        //looking for rule?\n        else if( (YES == [item isKindOfClass:[Rule class]]) &&\n                 (YES == [currentItem isKindOfClass:[Rule class]]) )\n        {\n            //rules match?\n            if(YES == [(Rule*)item isEqualToRule:(Rule*)currentItem])\n            {\n               //save index\n               row = i;\n               \n               //all done\n               break;\n            }\n        }\n        \n    }//all items\n    \n    return row;\n}\n\n\n//button handler\n// open LuLu home page/docs\n-(IBAction)openHomePage:(id)sender {\n    \n    //open\n    [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:PRODUCT_URL]];\n    \n    return;\n}\n\n//on window close\n// set activation policy\n-(void)windowWillClose:(NSNotification *)notification\n{\n    //cleanup any expired/temp rules\n    [xpcDaemonClient cleanupRules:NO];\n    \n    //wait a bit, then set activation policy\n    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),\n    ^{\n         //on main thread\n         dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{\n             \n             //set activation policy\n             [((AppDelegate*)[[NSApplication sharedApplication] delegate]) setActivationPolicy];\n             \n         });\n    });\n    \n    return;\n}\n\n@end\n"
  },
  {
    "path": "LuLu/App/SigningInfoViewController.h",
    "content": "//\n//  file: SigningInfoViewController\n//  project: lulu (login item)\n//  description: view controller for signing info popup (header)\n//\n//  created by Patrick Wardle\n//  copyright (c) 2018 Objective-See. All rights reserved.\n//\n\n@import Cocoa;\n\n/* DEFINES */\n\n//signing auths view\n#define SIGNING_AUTH_1 1\n\n@interface SigningInfoViewController : NSViewController <NSPopoverDelegate>\n{\n    \n}\n\n/* METHODS */\n\n\n/* PROPERTIES */\n\n//alert info\n@property(nonatomic, retain)NSDictionary* alert;\n\n//signing icon\n@property (weak) IBOutlet NSImageView* icon;\n\n//main signing msg\n@property (weak) IBOutlet NSTextField* message;\n\n//details\n@property (weak) IBOutlet NSTextField* details;\n\n@end\n"
  },
  {
    "path": "LuLu/App/SigningInfoViewController.m",
    "content": "//\n//  file: SigningInfoViewController\n//  project: lulu (login item)\n//  description: view controller for signing info popup (header)\n//\n//  created by Patrick Wardle\n//  copyright (c) 2018 Objective-See. All rights reserved.\n//\n\n#import \"consts.h\"\n#import \"utilities.h\"\n#import \"SigningInfoViewController.h\"\n\n@implementation SigningInfoViewController\n\n@synthesize alert;\n\n//automatically invoked\n-(void)popoverWillShow:(NSNotification *)notification;\n{\n    //signing info\n    NSDictionary* signingInfo = nil;\n    \n    //summary\n    NSMutableString* summary = nil;\n    \n    //signing ID\n    // default to blank\n    NSString* signingID = @\"\";\n    \n    //alloc string for summary\n    summary = [NSMutableString string];\n\n    //extract signing info\n    signingInfo = alert[KEY_CS_INFO];\n    \n    //start summary with item name\n    [summary appendString:alert[KEY_PROCESS_NAME]];\n    \n    //unset signing auth field\n    for(NSUInteger i=0; i<3; i++)\n    {\n        //unset\n        ((NSTextField*)[self.view viewWithTag:SIGNING_AUTH_1+i]).stringValue = @\"\";\n    }\n\n    //no signing info?\n    if(nil == signingInfo)\n    {\n        //append to summary\n        [summary appendFormat:NSLocalizedString(@\" is not validly signed\", @\" is not validly signed\")];\n        \n        //details: n/a\n        self.details.stringValue = NSLocalizedString(@\"not applicable\", @\"not applicable\");\n        \n        //bail\n        goto bail;\n    }\n\n    //process\n    switch([signingInfo[KEY_CS_STATUS] integerValue])\n    {\n        //happily signed\n        case noErr:\n            \n            //append to summary\n            [summary appendFormat:NSLocalizedString(@\" is validly signed\", @\" is validly signed\")];\n            \n            //set signing id\n            if(nil != signingInfo[KEY_CS_ID])\n            {\n                //set\n                signingID = signingInfo[KEY_CS_ID];\n            }\n            \n            //item signed by apple\n            if(Apple == [signingInfo[KEY_CS_SIGNER] intValue])\n            {\n                //set details\n                self.details.stringValue = [NSString stringWithFormat:NSLocalizedString(@\"%@ signed by Apple proper\", @\"%@ signed by Apple proper\"), signingID];\n            }\n            //item signed, third party/ad hoc, etc\n            else\n            {\n                //from app store?\n                if(AppStore == [signingInfo[KEY_CS_SIGNER] intValue])\n                {\n                    //set details\n                    self.details.stringValue = [NSString stringWithFormat:NSLocalizedString(@\"%@ signed by Mac App Store\", @\"%@ signed by Mac App Store\"), signingID];\n                }\n                //developer id?\n                else if(DevID == [signingInfo[KEY_CS_SIGNER] intValue])\n                {\n                    //set details\n                    self.details.stringValue = [NSString stringWithFormat:NSLocalizedString(@\"%@ signed with an Apple Developer ID\", @\"%@ signed with an Apple Developer ID\"), signingID];\n                }\n                //something else\n                // ad hoc? 3rd-party?\n                else if(AdHoc == [signingInfo[KEY_CS_SIGNER] intValue])\n                {\n                    //set details\n                    self.details.stringValue = [NSString stringWithFormat:NSLocalizedString(@\"%@ signed by 3rd-party/ad hoc\", @\"%@ signed by 3rd-party/ad hoc\"), signingID];\n                }\n                else\n                {\n                    //set details\n                    self.details.stringValue = NSLocalizedString(@\" unknown\", @\" unknown\");\n                }\n            }\n            \n            //no signing auths\n            // usually (always?) adhoc\n            if(0 == [signingInfo[KEY_CS_AUTHS] count])\n            {\n                //set signing auths field to none\n                ((NSTextField*)[self.view viewWithTag:SIGNING_AUTH_1]).stringValue = NSLocalizedString(@\"› no signing authorities\", @\"› no signing authorities\");\n            }\n            \n            //add each signing auth\n            // should one be max of three\n            else\n            {\n                //add signing auth\n                for(NSUInteger i=0; i<[signingInfo[KEY_CS_AUTHS] count]; i++)\n                {\n                    //exit loop at three\n                    if(i == 3) break;\n                        \n                    //add\n                    ((NSTextField*)[self.view viewWithTag:SIGNING_AUTH_1+i]).stringValue = [NSString stringWithFormat:@\"› %@ \\n\", signingInfo[KEY_CS_AUTHS][i]];\n                }\n            }\n            \n            break;\n            \n        //unsigned\n        case errSecCSUnsigned:\n            \n            //append to summary\n            [summary appendFormat:NSLocalizedString(@\" is not signed\", @\" is not signed\")];\n            \n            //details: n/a\n            self.details.stringValue = NSLocalizedString(@\"not applicable\", @\"not applicable\");\n            \n            //set signing auths field to n/a\n            ((NSTextField*)[self.view viewWithTag:SIGNING_AUTH_1]).stringValue = NSLocalizedString(@\"not applicable\", @\"not applicable\");\n            \n            break;\n            \n        //everything else\n        // other signing errors\n        default:\n            \n            //append to summary\n            [summary appendFormat:NSLocalizedString(@\" has a signing issue\", @\" has a signing issue\")];\n            \n            //set details\n            self.details.stringValue = [NSMutableString stringWithFormat:NSLocalizedString(@\"%@ signing error: %#lx\", @\"%@ signing error: %#lx\"), signingID, (long)[signingInfo[KEY_CS_STATUS] integerValue]];\n            \n            //set signing auths field to n/a\n            ((NSTextField*)[self.view viewWithTag:SIGNING_AUTH_1]).stringValue = NSLocalizedString(@\"not applicable\", @\"not applicable\");\n            \n            break;\n    }\n    \nbail:\n    \n    //assign summary to outlet\n    self.message.stringValue = summary;\n    \n    return;\n}\n\n@end\n"
  },
  {
    "path": "LuLu/App/StartupWindowController.h",
    "content": "//\n//  file: StartupWindowController.h\n//\n//  created by Patrick Wardle\n//  copyright (c) 2024 Objective-See. All rights reserved.\n//\n\n@import Cocoa;\n@import OSLog;\n\n@interface StartupWindowController : NSWindowController <NSWindowDelegate>\n{\n    \n}\n\n//version warning msg\n@property (weak) IBOutlet NSTextField *versionWarning;\n\n//activity indicator\n@property (weak) IBOutlet NSProgressIndicator *spinner;\n\n@end\n"
  },
  {
    "path": "LuLu/App/StartupWindowController.m",
    "content": "//\n//  file: StartupWindowController.m\n//\n//  created by Patrick Wardle\n//  copyright (c) 2024 Objective-See. All rights reserved.\n//\n\n#import \"consts.h\"\n#import \"utilities.h\"\n#import \"AppDelegate.h\"\n#import \"StartupWindowController.h\"\n\n/* GLOBALS */\n\n//log handle\nextern os_log_t logHandle;\n\n@implementation StartupWindowController\n\n@synthesize spinner;\n\n//automatically called when nib is loaded\n-(void)awakeFromNib\n{\n    //center\n    [self.window center];\n    \n    //start progress indicator\n    [self.spinner startAnimation:nil];\n    \n    //not in dark mode?\n    // make window white\n    if(YES != isDarkMode())\n    {\n        //make white\n        self.window.backgroundColor = NSColor.whiteColor;\n    }\n    \n    //set transparency\n    self.window.titlebarAppearsTransparent = YES;\n    \n    //need to display warning?\n    [self displayVersionWarning];\n    \n    //make it key window\n    [self.window makeKeyAndOrderFront:self];\n    \n    //activate\n    if(@available(macOS 14.0, *)) {\n        [NSApp activate];\n    }\n    else\n    {\n        [NSApp activateIgnoringOtherApps:YES];\n    }\n    \n    //(re)make front\n    [[NSRunningApplication currentApplication] activateWithOptions:(NSApplicationActivateAllWindows | NSApplicationActivateIgnoringOtherApps)];\n    \n    return;\n}\n\n//show version warning if on macOS 15, but less than 15.3\n-(void)displayVersionWarning\n{\n    //get OS version\n    NSOperatingSystemVersion version = NSProcessInfo.processInfo.operatingSystemVersion;\n\n    //default hide\n    self.versionWarning.hidden = YES;\n    \n    //macOS 15\n    // but less than 15.3? ...warn\n    if(version.majorVersion == 15 && version.minorVersion < 3) {\n        \n        //show warning\n        self.versionWarning.hidden = NO;\n    }\n\n    return;\n}\n\n@end\n"
  },
  {
    "path": "LuLu/App/StatusBarItem.h",
    "content": "//\n//  file: StatusBarMenu.h\n//  project: lulu (login item)\n//  description: menu handler for status bar icon (header)\n//\n//  created by Patrick Wardle\n//  copyright (c) 2017 Objective-See. All rights reserved.\n//\n\n\n@import Cocoa;\n@import OSLog;\n\n#import \"RulesMenuController.h\"\n\n@interface StatusBarItem : NSObject <NSPopoverDelegate, NSMenuDelegate>\n{\n\n}\n\n//status item\n@property(nonatomic, strong, readwrite)NSStatusItem* statusItem;\n\n//rules (sub)menu handler\n@property(nonatomic, retain)RulesMenuController* rulesMenuController;\n\n//popover\n@property(retain, nonatomic)NSPopover* popover;\n\n//disabled flag\n@property BOOL isDisabled;\n\n/* METHODS */\n\n//remove status item\n-(void)removeStatusItem;\n\n//init\n-(id)init:(NSMenu*)menu preferences:(NSDictionary*)preferences;\n\n//set to current profile\n-(void)setProfile;\n\n@end\n"
  },
  {
    "path": "LuLu/App/StatusBarItem.m",
    "content": "//\n//  file: StatusBarMenu.m\n//  project: lulu (login item)\n//  description: menu handler for status bar icon\n//\n//  created by Patrick Wardle\n//  copyright (c) 2017 Objective-See. All rights reserved.\n//\n\n#import \"consts.h\"\n#import \"utilities.h\"\n#import \"Extension.h\"\n#import \"AppDelegate.h\"\n#import \"StatusBarItem.h\"\n#import \"StatusBarPopoverController.h\"\n\n/* GLOBALS */\n\n//log handle\nextern os_log_t logHandle;\n\n//xpc for daemon comms\nextern XPCDaemonClient* xpcDaemonClient;\n\n//menu items\nenum menuItems\n{\n    status = 100,\n    profile,\n    toggle,\n    rulesShow,\n    rulesAdd,\n    rulesExport,\n    rulesImport,\n    rulesCleanup,\n    profilesManage,\n    prefs,\n    monitor,\n    quit,\n    uninstall,\n    support,\n    end\n};\n\n@implementation StatusBarItem\n\n@synthesize isDisabled;\n@synthesize statusItem;\n@synthesize rulesMenuController;\n\n//init method\n// set some intial flags, init daemon comms, etc.\n-(id)init:(NSMenu*)menu preferences:(NSDictionary*)preferences\n{\n    //token\n    static dispatch_once_t onceToken = 0;\n    \n    //super\n    self = [super init];\n    if(self != nil)\n    {\n        //init rules (sub)menu handler\n        rulesMenuController = [[RulesMenuController alloc] init];\n        \n        //create item\n        [self createStatusItem:menu];\n        \n        //set state based on (existing) preferences\n        self.isDisabled = [preferences[PREF_IS_DISABLED] boolValue];\n        \n        //only once\n        // show popover\n        dispatch_once(&onceToken, ^{\n            \n            //parent\n            NSDictionary* parent = nil;\n            \n            //get real parent\n            parent = getRealParent(getpid());\n            \n            //dbg msg\n            os_log_debug(logHandle, \"(real) parent: %{public}@\", parent);\n            \n            //only show popover if we're not autolaunched\n            if(YES != [parent[@\"CFBundleIdentifier\"] isEqualToString:@\"com.apple.loginwindow\"])\n            {\n                //dbg msg\n                os_log_debug(logHandle, \"...user launched, so will show status bar popover\");\n                \n                //show\n                [self showPopover];\n            }\n            \n        });\n    \n        //set initial menu state\n        [self setState];\n    }\n    \n    return self;\n}\n\n//create status item\n-(void)createStatusItem:(NSMenu*)menu\n{\n    //init status item\n    statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength];\n    \n    //set menu / delegate\n    self.statusItem.menu = menu;\n    self.statusItem.menu.delegate = self;\n    \n    //set handler for each menu item\n    [self setMenuHandler:menu];\n    \n    //disable first two menu items\n    // as they are purely informative\n    [menu.itemArray[0] setEnabled:NO];\n    [menu.itemArray[0] setAction:nil];\n    [menu.itemArray[1] setEnabled:NO];\n    [menu.itemArray[1] setAction:nil];\n    \n    //init profiles items/sub-menu\n    [self setProfile];\n    \n    return;\n}\n\n//menu 'will open' delegate\n// make sure popover is closed\n-(void)menuWillOpen:(NSMenu *)menu\n{\n    //make sure to close popover first\n    if(YES == self.popover.shown)\n    {\n        //close\n        [self.popover performClose:nil];\n    }\n    \n    return;\n}\n\n//set handler for menu item(s)\n-(void)setMenuHandler:(NSMenu*)menu\n{\n    //iterate over all menu items\n    // add target, enable, and handler for each\n    for(NSMenuItem* menuItem in menu.itemArray)\n    {\n        //handle sub-menu(s)\n        if(nil != menuItem.submenu)\n        {\n            //recursively set actions for submenu items\n            [self setMenuHandler:menuItem.submenu];\n            \n            continue;\n        }\n        \n        //set target\n        menuItem.target = self;\n        \n        //enable\n        menuItem.enabled = YES;\n        \n        //set action, to handler\n        menuItem.action = @selector(handler:);\n    }\n    return;\n}\n\n//remove status item\n-(void)removeStatusItem\n{\n    //remove item\n    [[NSStatusBar systemStatusBar] removeStatusItem:self.statusItem];\n    \n    //unset\n    self.statusItem = nil;\n    \n    return;\n}\n\n//show popver\n-(void)showPopover\n{\n    //alloc popover\n    self.popover = [[NSPopover alloc] init];\n    \n    //don't want highlight for popover\n    self.statusItem.button.cell.highlighted = NO;\n    \n    //set target\n    self.statusItem.button.target = self;\n    \n    //set view controller\n    self.popover.contentViewController = [[StatusBarPopoverController alloc] initWithNibName:@\"StatusBarPopover\" bundle:nil];\n    \n    //set behavior\n    // don't want it close before timeout (unless user clicks '^')\n    self.popover.behavior = NSPopoverBehaviorApplicationDefined;\n    \n    //set delegate\n    self.popover.delegate = self;\n    \n    //show popover\n    // have to wait cuz...\n    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5 * NSEC_PER_SEC), dispatch_get_main_queue(),\n    ^{\n        //show\n        [self.popover showRelativeToRect:self.statusItem.button.bounds ofView:self.statusItem.button preferredEdge:NSMinYEdge];\n    });\n\n    //wait a bit\n    // then automatically hide popup if user has not closed it\n    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC), dispatch_get_main_queue(),\n    ^{\n        //still visible?\n        // close it then...\n        if(YES == self.popover.shown)\n        {\n            //close\n            [self.popover performClose:nil];\n        }\n            \n        //remove action handler\n        self.statusItem.button.action = nil;\n        \n        //reset highlight mode\n        ((NSButtonCell*)self.statusItem.button.cell).highlightsBy = NSContentsCellMask | NSChangeBackgroundCellMask;\n    });\n    \n    return;\n}\n\n//cleanup popover\n-(void)popoverDidClose:(NSNotification *)notification\n{\n    //unset\n    self.popover = nil;\n    \n    //reset highlight mode\n    ((NSButtonCell*)self.statusItem.button.cell).highlightsBy = NSContentsCellMask | NSChangeBackgroundCellMask;\n    \n    return;\n}\n\n//menu handler\n-(void)handler:(id)sender\n{\n    //dbg msg\n    os_log_debug(logHandle, \"handling button click: %{public}@ (%ld)\", ((NSButton*)sender).title, ((NSButton*)sender).tag);\n    \n    //handle user selection\n    switch(((NSMenuItem*)sender).tag)\n    {\n        //toggle\n        case toggle:\n        {\n            //dbg msg\n            os_log_debug(logHandle, \"toggling (%d -> %d)\", self.isDisabled, !self.isDisabled);\n        \n            //invert since toggling\n            self.isDisabled = !self.isDisabled;\n        \n            //set menu state\n            [self setState];\n        \n            //update prefs\n            [xpcDaemonClient updatePreferences:@{PREF_IS_DISABLED:[NSNumber numberWithBool:self.isDisabled]}];\n            \n            //toggle network extension based on (new) state\n            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),\n            ^{\n                //toggle\n                [[[Extension alloc] init] toggleNetworkExtension:!self.isDisabled];\n            });\n            \n            break;\n        }\n           \n        //rules: show\n        case rulesShow:\n            \n            //show\n            [self.rulesMenuController showRules];\n            \n            break;\n            \n        //rules: add\n        case rulesAdd:\n            \n            //show first\n            [self.rulesMenuController showRules];\n            \n            //add\n            [self.rulesMenuController addRule];\n            \n            break;\n            \n        //rules: export\n        case rulesExport:\n            \n            //show first\n            [self.rulesMenuController showRules];\n            \n            //export\n            [self.rulesMenuController exportRules];\n            \n            break;\n        \n        //rules: import\n        case rulesImport:\n            \n            //import\n            if(YES != [self.rulesMenuController importRules])\n            {\n                //show alert\n                showAlert(NSAlertStyleWarning, NSLocalizedString(@\"ERROR: Failed to import rules\", @\"ERROR: Failed to import rules\"), NSLocalizedString(@\"See log for (more) details\",@\"See log for (more) details\"), @[NSLocalizedString(@\"OK\", @\"OK\")]);\n                \n                //bail\n                goto bail;\n            }\n            \n            //then show rules\n            [self.rulesMenuController showRules];\n            \n            break;\n            \n        //rules: cleanup\n        case rulesCleanup:\n            \n            //cleanup\n            if([self.rulesMenuController cleanupRules] < 0)\n            {\n                //show alert\n                showAlert(NSAlertStyleWarning, NSLocalizedString(@\"ERROR: Failed to cleanup rules\", @\"ERROR: Failed to cleanup rules\"), NSLocalizedString(@\"See log for (more) details\",@\"See log for (more) details\"), @[NSLocalizedString(@\"OK\",@\"OK\")]);\n                \n                //bail\n                goto bail;\n            }\n            break;\n        \n        //profiles\n        case profilesManage:\n            [((AppDelegate*)[[NSApplication sharedApplication] delegate]) showPreferences:TOOLBAR_PROFILES_ID];\n            break;\n            \n        //prefs\n        // default to rules\n        case prefs:\n            [((AppDelegate*)[[NSApplication sharedApplication] delegate]) showPreferences:TOOLBAR_RULES_ID];\n            break;\n            \n        //monitor\n        // launch netiquette (with lulu args)\n        case monitor:\n        {\n            //path\n            NSURL* path = nil;\n           \n            //error\n            NSError* error = nil;\n           \n            //init path\n            path = [NSURL fileURLWithPath:[NSBundle.mainBundle.resourcePath stringByAppendingPathComponent:NETWORK_MONITOR]];\n            \n            //dbg msg\n            os_log_debug(logHandle, \"launching network monitor (%{public}@)\", path);\n            \n            //launch\n            // with args\n            if(nil == [NSWorkspace.sharedWorkspace launchApplicationAtURL:path options:0 configuration:[NSDictionary dictionaryWithObject:@[@\"-lulu\"] forKey:NSWorkspaceLaunchConfigurationArguments] error:&error])\n            {\n                //err msg\n                os_log_error(logHandle, \"ERROR: failed to launch network monitor, %{public}@, (error: %{public}@)\", path, error);\n            }\n            \n            break;\n        }\n            \n        //quit\n        case quit:\n            [((AppDelegate*)[[NSApplication sharedApplication] delegate]) quit:sender];\n            break;\n            \n        //uninstall\n        case uninstall:\n            [((AppDelegate*)[[NSApplication sharedApplication] delegate]) uninstall:sender];\n            break;\n            \n        //support\n        case support:\n            \n            //open URL\n            // invokes user's default browser\n            [NSWorkspace.sharedWorkspace openURL:[NSURL URLWithString:PATREON_URL]];\n            break;\n        \n        default:\n            \n            break;\n    }\n    \nbail:\n    \n    return;\n}\n\n//set current profile\n-(void)setProfile\n{\n    //current\n    NSString* current = [xpcDaemonClient getCurrentProfile];\n    \n    //profiles\n    NSMutableArray* profiles = [xpcDaemonClient getProfiles];\n    \n    //grab menu\n    NSMenu* menu = [((AppDelegate*)[[NSApplication sharedApplication] delegate]) profilesMenu];\n    \n    //set current profile\n    if(nil != current)\n    {\n        //set\n        [self.statusItem.menu itemWithTag:profile].title = [NSString stringWithFormat:NSLocalizedString(@\"Profile: %@\", @\"Profile: %@\"), current];\n    }\n    //otherwise (re)set to default\n    else\n    {\n        //set\n        [self.statusItem.menu itemWithTag:profile].title = NSLocalizedString(@\"Profile: Default\", @\"Profile: Default\");\n    }\n    \n    //reset profiles menu\n    [menu removeAllItems];\n    \n    //have profiles?\n    // add each name and enable 'Switch' menu item\n    if(0 != profiles.count)\n    {\n        //enable\n        [[((AppDelegate*)[[NSApplication sharedApplication] delegate]) profileSwitchMenuItem] setEnabled:YES];\n        \n        //add default first/top\n        [profiles insertObject:NSLocalizedString(@\"Default\", @\"Default\") atIndex:0];\n        \n        //add each name\n        for(NSString *name in profiles)\n        {\n            //menu item\n            NSMenuItem* item = [[NSMenuItem alloc] initWithTitle:name action:@selector(switchToProfile:) keyEquivalent:@\"\"];\n            \n            //target\n            item.target = self;\n            \n            //default to off\n            item.state = NSControlStateValueOff;\n            \n            //name\n            // though keep default 'nil'\n            if(NSOrderedSame != [name caseInsensitiveCompare:NSLocalizedString(@\"Default\", @\"Default\")])\n            {\n                //set\n                item.representedObject = name;\n            }\n            \n            //add\n            [menu addItem:item];\n            \n            //should select 'default' as current?\n            if( (nil == current) &&\n                (NSOrderedSame == [name caseInsensitiveCompare:NSLocalizedString(@\"Default\", @\"Default\")]) )\n            {\n                //set\n                item.state = NSControlStateValueOn;\n            }\n            \n            //should select other as current?\n            else if(YES == [item.title isEqualToString:current])\n            {\n                //set\n                item.state = NSControlStateValueOn;\n            }\n        }\n    }\n    //otherwise disable\n    else\n    {\n        //disable\n        [[((AppDelegate*)[[NSApplication sharedApplication] delegate]) profileSwitchMenuItem] setEnabled:NO];\n    }\n    \n    return;\n}\n\n//switch profile\n- (void)switchToProfile:(NSMenuItem *)sender {\n    \n    //grab profile\n    NSString* profile = sender.representedObject;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"user wants to change profile to '%{public}@'\", profile ? profile : @\"Default\");\n    \n    //set profile via XPC\n    // nil is ok, means (re)set to default\n    [xpcDaemonClient setProfile:profile];\n    \n    //tell app profiles changed\n    // will also update status menu\n    [((AppDelegate*)[[NSApplication sharedApplication] delegate]) profilesChanged];\n    \n    //tell app preferences changed\n    [((AppDelegate*)[[NSApplication sharedApplication] delegate]) preferencesChanged:[xpcDaemonClient getPreferences]];\n    \n    //show alert\n    showAlert(NSAlertStyleInformational, NSLocalizedString(@\"Profile Switched\", @\"Profile Switched\"), [NSString stringWithFormat:NSLocalizedString(@\"Current profile is now: '%@'.\", @\"Current profile is now: '%@'.\"), nil != profile ? profile : NSLocalizedString(@\"Default\", @\"Default\")], @[NSLocalizedString(@\"OK\", @\"OK\")]);\n    \n    return;\n}\n\n\n//set menu status\n// logic based on 'isEnabled' iVar\n-(void)setState\n{\n    //dbg msg\n    os_log_debug(logHandle, \"setting state to: %@\", (self.isDisabled) ? @\"disabled\" : @\"enabled\");\n    \n    //set to disabled\n    if(YES == self.isDisabled)\n    {\n        //update status\n        [self.statusItem.menu itemWithTag:status].title = NSLocalizedString(@\"LuLu: disabled\", @\"LuLu: disabled\");\n        \n        //set icon\n        self.statusItem.button.image = [NSImage imageNamed:@\"StatusInactive\"];\n        \n        //change toggle text\n        [self.statusItem.menu itemWithTag:toggle].title = NSLocalizedString(@\"Enable\", @\"Enable\");\n    }\n    \n    //set to enabled\n    else\n    {\n        //update status\n        [self.statusItem.menu itemWithTag:status].title = NSLocalizedString(@\"LuLu: enabled\", @\"LuLu: enabled\");\n        \n        //set icon\n        self.statusItem.button.image = [NSImage imageNamed:@\"StatusActive\"];\n        \n        //change toggle text\n        [self.statusItem.menu itemWithTag:toggle].title = NSLocalizedString(@\"Disable\", @\"Disable\");\n    }\n    \n    return;\n}\n\n@end\n"
  },
  {
    "path": "LuLu/App/StatusBarPopoverController.h",
    "content": "//\n//  file: StatusBarPopoverController.h\n//  project: lulu (login item)\n//  description: popover for status bar (header)\n//\n//  created by Patrick Wardle\n//  copyright (c) 2017 Objective-See. All rights reserved.\n//\n\n@import Cocoa;\n\n@interface StatusBarPopoverController : NSViewController\n\n@end\n"
  },
  {
    "path": "LuLu/App/StatusBarPopoverController.m",
    "content": "//\n//  file: StatusBarPopoverController.m\n//  project: lulu (login item)\n//  description: popover for status bar\n//\n//  created by Patrick Wardle\n//  copyright (c) 2017 Objective-See. All rights reserved.\n//\n\n#import \"AppDelegate.h\"\n#import \"StatusBarPopoverController.h\"\n\n@implementation StatusBarPopoverController\n\n//'close' button handler\n// simply dismiss/close popover\n-(IBAction)closePopover:(NSControl *)sender\n{\n    //close\n    [[[self view] window] close];\n    \n    return;\n}\n\n@end\n"
  },
  {
    "path": "LuLu/App/Update.h",
    "content": "//\n//  file: Update.h\n//  project: lulu (shared)\n//  description: checks for new versions of LuLu (header)\n//\n//  created by Patrick Wardle\n//  copyright (c) 2017 Objective-See. All rights reserved.\n//\n\n\n#ifndef Update_h\n#define Update_h\n\n@import Cocoa;\n@import Foundation;\n\n@interface Update : NSObject\n\n//check for an update\n// will invoke app delegate method to update UI when check completes\n-(void)checkForUpdate:(void (^)(NSUInteger result, NSString* latestVersion))completionHandler;\n\n@end\n\n\n#endif /* Update_h */\n"
  },
  {
    "path": "LuLu/App/Update.m",
    "content": "//\n//  file: Update.m\n//  project: lulu (shared)\n//  description: checks for new versions of LuLu\n//\n//  created by Patrick Wardle\n//  copyright (c) 2017 Objective-See. All rights reserved.\n//\n\n#import \"consts.h\"\n#import \"Update.h\"\n#import \"utilities.h\"\n#import \"AppDelegate.h\"\n\n/* GLOBALS */\n\n//log handle\nextern os_log_t logHandle;\n\n@implementation Update\n\n//check for an update\n// will invoke app delegate method to update UI when check completes\n-(void)checkForUpdate:(void (^)(NSUInteger result, NSString* latestVersion))completionHandler\n{\n    //get latest version in background\n    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{\n        \n        //result\n        NSInteger result = Update_None;\n\n        //product info\n        NSDictionary* productInfo = nil;\n        \n        //latest version\n        NSString* latestVersion = nil;\n        \n        //major/minor\n        NSNumber* osMajor = nil;\n        NSNumber* osMinor = nil;\n        \n        //get product info\n        productInfo = [self getProductInfo:PRODUCT_NAME];\n        if(nil != productInfo)\n        {\n            //first check if there is a new version\n            latestVersion = productInfo[LATEST_VERSION];\n            if(YES == [latestVersion isKindOfClass:[NSString class]])\n            {\n                //trim\n                latestVersion = [latestVersion stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];\n                \n                //check current version with latest\n                if(NSOrderedAscending == [getAppVersion() compare:latestVersion options:NSNumericSearch])\n                {\n                    //update available\n                    result = Update_Available;\n                }\n            }\n            \n            //then check if new version is compatible w/ user version of macOS\n            if(result == Update_Available)\n            {\n                osMajor = productInfo[SUPPORTED_OS_MAJOR];\n                osMinor = productInfo[SUPPORTED_OS_MINOR];\n                \n                if( (YES == [osMajor isKindOfClass:[NSNumber class]]) &&\n                    (YES == [osMinor isKindOfClass:[NSNumber class]]) )\n                {\n                    //init\n                    NSOperatingSystemVersion supportedOS = {\n                        .majorVersion = osMajor.intValue,\n                        .minorVersion = osMinor.intValue,\n                        .patchVersion = 0\n                    };\n                    \n                    //user's version of macOS supported?\n                    if(YES != [NSProcessInfo.processInfo isOperatingSystemAtLeastVersion:supportedOS])\n                    {\n                        //dbg mdg\n                        os_log_debug(logHandle, \"Latest version requires macOS %ld.%ld, but current macOS is %{public}@\", supportedOS.majorVersion, supportedOS.minorVersion, NSProcessInfo.processInfo.operatingSystemVersionString);\n                        \n                        //not supported\n                        result = Update_NotSupported;\n                    }\n                }\n            }\n        }\n        //error\n        else\n        {\n            //err msg\n            os_log_error(logHandle, \"ERROR: Failed to retrieve product info (for update check) from %{public}@\", PRODUCT_VERSIONS_URL);\n            \n            result = Update_Error;\n        }\n         \n        //invoke app delegate method\n        // will update UI/show popup if necessary\n        dispatch_async(dispatch_get_main_queue(),\n        ^{\n            completionHandler(result, latestVersion);\n        });\n    });\n    \n    return;\n}\n\n//read JSON file w/ products\n// return dictionary w/ info about this product\n-(NSDictionary*)getProductInfo:(NSString*)product\n{\n    //product version(s) data\n    NSData* json = nil;\n    NSError* error = nil;\n    NSDictionary* products = nil;\n    NSDictionary* productInfo = nil;\n\n    //get json file (products) from remote URL\n    @try\n    {\n        //get JSON\n        json = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:PRODUCT_VERSIONS_URL]];\n        if(nil == json)\n        {\n            //err msg\n            os_log_error(logHandle, \"ERROR: failed to download product info from %{public}@\", PRODUCT_VERSIONS_URL);\n            goto bail;\n        }\n        \n        //convert\n        products = [NSJSONSerialization JSONObjectWithData:json options:0 error:&error];\n        if(nil != error)\n        {\n            //err msg\n            os_log_error(logHandle, \"ERROR: Failed to convert 'products' to JSON (error: %{public}@)\", error);\n            goto bail;\n        }\n        \n        //extract product info\n        if( (YES == [products isKindOfClass:[NSDictionary class]]) &&\n            (YES == [products[product] isKindOfClass:[NSDictionary class]]) )\n        {\n            productInfo = products[product];\n        }\n    }\n    @catch(NSException* exception)\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: Failed to convert 'products' to JSON (exception: %{public}@)\", exception);\n    }\n\nbail:\n    \n    return productInfo;\n}\n\n@end\n"
  },
  {
    "path": "LuLu/App/UpdateWindowController.h",
    "content": "//\n//  file: UpdateWindowController.m\n//  project: lulu\n//  description: window handler for update window/popup (header)\n//\n//  created by Patrick Wardle\n//  copyright (c) 2020 Objective-See. All rights reserved.\n//\n\n@import Cocoa;\n\n@interface UpdateWindowController : NSWindowController <NSWindowDelegate>\n{\n    \n}\n\n/* PROPERTIES */\n\n//version label/string\n@property(weak)IBOutlet NSTextField *infoLabel;\n\n//action button\n@property(weak)IBOutlet NSButton *actionButton;\n\n//label string\n@property(nonatomic, retain)NSString* infoLabelString;\n\n\n/* METHODS */\n\n//save the main label\n-(void)configure:(NSString*)label;\n\n//invoked when user clicks button\n// ->trigger action such as opening product website, updating, etc\n-(IBAction)buttonHandler:(id)sender;\n\n@end\n"
  },
  {
    "path": "LuLu/App/UpdateWindowController.m",
    "content": "//\n//  file: UpdateWindowController.m\n//  project: lulu\n//  description: window handler for update window/popup\n//\n//  created by Patrick Wardle\n//  copyright (c) 2020 Objective-See. All rights reserved.\n//\n\n#import \"consts.h\"\n#import \"utilities.h\"\n#import \"AppDelegate.h\"\n#import \"UpdateWindowController.h\"\n\n@implementation UpdateWindowController\n\n@synthesize infoLabel;\n@synthesize actionButton;\n@synthesize infoLabelString;\n\n//automatically called when nib is loaded\n-(void)awakeFromNib\n{\n    //center\n    [self.window center];\n    \n    return;\n}\n\n//automatically invoked when window is loaded\n-(void)windowDidLoad\n{\n    //super\n    [super windowDidLoad];\n    \n    //not in dark mode?\n    // make window white\n    if(YES != isDarkMode())\n    {\n        //make white\n        self.window.backgroundColor = NSColor.whiteColor;\n    }\n    \n    //indicated title bar is transparent (too)\n    self.window.titlebarAppearsTransparent = YES;\n    \n    //set main label\n    self.infoLabel.stringValue = self.infoLabelString;\n        \n    //make button first responder\n    // calling this without a timeout sometimes fails :/\n    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (100 * NSEC_PER_MSEC)), dispatch_get_main_queue(), ^{\n        \n        //make first responder\n        [self.window makeFirstResponder:self.actionButton];\n        \n    });\n\n    //make it key window\n    [self.window makeKeyAndOrderFront:self];\n    \n    //activate\n    if(@available(macOS 14.0, *)) {\n        [NSApp activate];\n    }\n    else\n    {\n        [NSApp activateIgnoringOtherApps:YES];\n    }\n    \n    //(re)make front\n    [[NSRunningApplication currentApplication] activateWithOptions:(NSApplicationActivateAllWindows | NSApplicationActivateIgnoringOtherApps)];\n    \n    return;\n}\n\n//automatically invoked when window is closing\n// ->make ourselves unmodal\n-(void)windowWillClose:(NSNotification *)notification\n{\n    //make un-modal\n    [[NSApplication sharedApplication] stopModal];\n    \n    return;\n}\n\n//save the main label\n-(void)configure:(NSString*)label\n{\n    //save label's string\n    self.infoLabelString = label;\n    \n    return;\n}\n\n//invoked when user clicks button\n-(IBAction)buttonHandler:(id)sender\n{\n    //open URL\n    [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:PRODUCT_URL]];\n    \n    //always close window\n    [[self window] close];\n        \n    return;\n}\n@end\n"
  },
  {
    "path": "LuLu/App/WelcomeWindowController.h",
    "content": "//\n//  LinkWindowController.h\n//  LuLu\n//\n//  Created by Patrick Wardle on 1/25/18.\n//  Copyright (c) 2018 Objective-See. All rights reserved.\n//\n\n@import Cocoa;\n@import OSLog;\n\n#import \"XPCDaemonClient.h\"\n\n@interface WelcomeWindowController : NSWindowController\n\n/* PROPERTIES */\n\n//main view controller\n@property(nonatomic, retain)NSViewController* welcomeViewController;\n\n//welcome view\n@property (strong) IBOutlet NSView *welcomeView;\n\n//allow extension view\n@property (strong) IBOutlet NSView *allowExtensionView;\n\n//allow extension spinner\n@property (weak) IBOutlet NSProgressIndicator *allowExtActivityIndicator;\n\n//allow extension message\n@property (weak) IBOutlet NSTextField *allowExtMessage;\n\n//approve extension image\n@property (weak) IBOutlet NSImageView *approveExt;\n\n//approve extension message\n@property (weak) IBOutlet NSTextField *approveExtMessage;\n\n//config view\n@property (strong) IBOutlet NSView *configureView;\n\n//allow apple bins/apps\n@property (weak) IBOutlet NSButton *allowApple;\n\n//allow 3rd-party installed apps\n@property (weak) IBOutlet NSButton *allowInstalled;\n\n//allow dns traffic installed apps\n@property (weak) IBOutlet NSButton *allowDNS;\n\n//support view\n@property (strong) IBOutlet NSView *supportView;\n\n//preferences\n@property (nonatomic, retain)NSDictionary* preferences;\n\n/* METHODS */\n\n//show a view\n// note: replaces old view and highlights specified responder\n-(void)showView:(NSView*)view firstResponder:(NSInteger)firstResponder;\n\n@end\n"
  },
  {
    "path": "LuLu/App/WelcomeWindowController.m",
    "content": "//\n//  file: WelcomeWindowController.m\n//  project: lulu (main app)\n//  description: menu handler for status bar icon\n//\n//  created by Patrick Wardle\n//  copyright (c) 2017 Objective-See. All rights reserved.\n//\n\n#import \"consts.h\"\n#import \"utilities.h\"\n#import \"Extension.h\"\n#import \"AppDelegate.h\"\n#import \"XPCDaemonClient.h\"\n#import \"WelcomeWindowController.h\"\n\n/* GLOBALS */\n\n//log handle\nextern os_log_t logHandle;\n\n//buttons\n#define SHOW_WELCOME 0\n#define SHOW_ALLOW_EXT 1\n#define SHOW_CONFIGURE 2\n#define SHOW_SUPPORT 3\n#define SUPPORT_NO 4\n#define SUPPORT_YES 5\n\n@implementation WelcomeWindowController\n\n@synthesize preferences;\n@synthesize welcomeViewController;\n\n//welcome!\n-(void)windowDidLoad {\n    \n    //super\n    [super windowDidLoad];\n    \n    //not in dark mode?\n    // make window white\n    if(YES != isDarkMode())\n    {\n        //make white\n        self.window.backgroundColor = NSColor.whiteColor;\n    }\n    \n    //when supported\n    // indicate title bar is transparent (too)\n    if(YES == [self.window respondsToSelector:@selector(titlebarAppearsTransparent)])\n    {\n        //set transparency\n        self.window.titlebarAppearsTransparent = YES;\n    }\n    \n    //set title\n    self.window.title = [NSString stringWithFormat:@\"LuLu v%@\", getAppVersion()];\n    \n    //show welcome view\n    [self showView:self.welcomeView firstResponder:SHOW_ALLOW_EXT];\n    \n    //make key and front\n    [self.window makeKeyAndOrderFront:self];\n    \n    //activate\n    if(@available(macOS 14.0, *)) {\n        [NSApp activate];\n    }\n    else\n    {\n        [NSApp activateIgnoringOtherApps:YES];\n    }\n    \n    //(re)make front\n    [[NSRunningApplication currentApplication] activateWithOptions:(NSApplicationActivateAllWindows | NSApplicationActivateIgnoringOtherApps)];\n    \n    return;\n}\n\n//button handler for all views\n// show next view, sometimes, with view specific logic\n-(IBAction)buttonHandler:(id)sender {\n    \n    //leaving prefs view?\n    // capture prefs/set defaults\n    if( (SHOW_CONFIGURE+1) == ((NSToolbarItem*)sender).tag)\n    {\n        //capture\n        self.preferences = @{PREF_ALLOW_APPLE:[NSNumber numberWithBool:self.allowApple.state], PREF_ALLOW_INSTALLED: [NSNumber numberWithBool:self.allowInstalled.state], PREF_ALLOW_DNS: [NSNumber numberWithBool:self.allowDNS.state], PREF_ALLOW_LOCALHOST:@YES, PREF_ALLOW_SIMULATOR:@NO, PREF_PASSIVE_MODE:@NO, PREF_PASSIVE_MODE_ACTION:@0, PREF_BLOCK_MODE:@NO, PREF_NO_ICON_MODE:@NO, PREF_NO_VT_MODE:@NO, PREF_NO_UPDATE_MODE:@NO, PREF_INSTALL_TIMESTAMP:[NSDate date]};\n    }\n    \n    //set next view\n    switch(((NSButton*)sender).tag)\n    {\n        //show \"allow extension\" view\n        // waits until extension is loaded!\n        case SHOW_ALLOW_EXT:\n        {\n            //skip if extension is already active\n            if(YES == [[[Extension alloc] init] isNetworkExtensionEnabled])\n            {\n                //dbg msg\n                os_log_debug(logHandle, \"network extension already enabled, jumping to 'configure' view\");\n                \n                //goto to next view!\n                [self showView:self.configureView firstResponder:SHOW_SUPPORT];\n                \n                //done\n                break;\n            }\n            \n            //show view\n            [self showView:self.allowExtensionView firstResponder:-1];\n            \n            //macOS 15\n            // set image and instructions\n            if(@available(macOS 15.0, *)) {\n                \n                //set image\n                self.approveExt.image = [NSImage imageNamed:@\"InstallApprove\"];\n                \n                //set instructions\n                self.approveExtMessage.stringValue = NSLocalizedString(@\"2. In System Settings, toggle on the LuLu extension\", @\"2. In System Settings, toggle on the LuLu extension\");\n            }\n            //pre-macOS 15\n            // set (older) image and (older) instructions\n            else\n            {\n                //set image\n                self.approveExt.image = [NSImage imageNamed:@\"InstallApprove_OLD\"];\n                \n                //set instructions\n                self.approveExtMessage.stringValue = NSLocalizedString(@\"2. In System Settings, scroll to where it mentions 'LuLu' and click 'Allow'\", @\"2. In System Settings, scroll to where it mentions 'LuLu' and click 'Allow'\");\n            }\n            \n            //show message\n            self.allowExtMessage.hidden = NO;\n            \n            //show spinner\n            self.allowExtActivityIndicator.hidden = NO;\n            \n            //start spinner\n            [self.allowExtActivityIndicator startAnimation:nil];\n            \n            //in background\n            // activate and wait for extension to be approved\n            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),\n            ^{\n                //extension\n                Extension* extension = nil;\n                \n                //wait semaphore\n                dispatch_semaphore_t semaphore = 0;\n                \n                //init extension object\n                extension = [[Extension alloc] init];\n                \n                //init wait semaphore\n                semaphore = dispatch_semaphore_create(0);\n                \n                //kick off extension activation request\n                [extension toggleExtension:ACTION_ACTIVATE reply:^(NSError* error) {\n                    \n                    //dbg msg\n                    os_log_debug(logHandle, \"extension 'activate' returned\");\n                    \n                    //error\n                    if(error)\n                    {\n                        //err msg\n                        os_log_error(logHandle, \"ERROR: failed to activate system extension\");\n                        \n                        //show alert/exit on main thread\n                        dispatch_async(dispatch_get_main_queue(),\n                        ^{\n                            //show alert\n                            showAlert(NSAlertStyleCritical, NSLocalizedString(@\"ERROR: activation failed\", @\"ERROR: activation failed\"), NSLocalizedString(@\"failed to activate system extension\", @\"failed to activate system extension\"), @[NSLocalizedString(@\"OK\", @\"OK\")]);\n                            \n                            //bye\n                            [NSApplication.sharedApplication terminate:self];\n                        });\n                    }\n                    \n                    //dbg msg\n                    os_log_debug(logHandle, \"system extension activated\");\n                     \n                    //update message on main thread\n                    dispatch_sync(dispatch_get_main_queue(),\n                    ^{\n                        //update UI\n                        self.allowExtMessage.stringValue = NSLocalizedString(@\"Waiting for Network Extension Approval\", @\"Waiting for Network Extension Approval\");\n                    });\n                    \n                    //activate network extension\n                    if(YES != [extension toggleNetworkExtension:ACTION_ACTIVATE])\n                    {\n                        //err msg\n                        os_log_error(logHandle, \"ERROR: failed to activate network extension\");\n                        \n                        //show alert/exit on main thread\n                        dispatch_async(dispatch_get_main_queue(),\n                        ^{\n                            //show alert\n                            showAlert(NSAlertStyleCritical, NSLocalizedString(@\"ERROR: activation failed\",@\"ERROR: activation failed\"), NSLocalizedString(@\"failed to activate network extension\",@\"failed to activate network extension\"), @[NSLocalizedString(@\"OK\", @\"OK\")]);\n                            \n                            //bye\n                            [NSApplication.sharedApplication terminate:self];\n                        });\n                    }\n                    \n                    //dbg msg\n                    os_log_debug(logHandle, \"network filter approved/enabled\");\n                    \n                    //update UI\n                    dispatch_sync(dispatch_get_main_queue(),\n                    ^{\n                        //hide spinner\n                        self.allowExtActivityIndicator.hidden = YES;\n                        \n                        //hide message\n                        self.allowExtMessage.hidden = YES;\n                        \n                        //goto to next view!\n                        [self showView:self.configureView firstResponder:SHOW_SUPPORT];\n                        \n                        //make it key window\n                        [self.window makeKeyAndOrderFront:self];\n                        \n                        //activate\n                        if(@available(macOS 14.0, *)) {\n                            [NSApp activate];\n                        }\n                        else\n                        {\n                            [NSApp activateIgnoringOtherApps:YES];\n                        }\n                        \n                        //(re)make front\n                        [[NSRunningApplication currentApplication] activateWithOptions:(NSApplicationActivateAllWindows | NSApplicationActivateIgnoringOtherApps)];\n                        \n                    });\n                    \n                    //signal semaphore\n                    dispatch_semaphore_signal(semaphore);\n                    \n                }];\n                \n                //wait for extension semaphore\n                dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);\n                \n            });\n            \n            break;\n        }\n            \n        //show configure view\n        case SHOW_CONFIGURE:\n            \n            //show\n            [self showView:self.configureView firstResponder:SHOW_SUPPORT];\n            \n            break;\n            \n        //show \"support us\" view\n        // + kick off main logic so traffic filtering is started\n        case SHOW_SUPPORT:\n            \n            //show support view\n            [self showView:self.supportView firstResponder:SUPPORT_YES];\n            \n            //kick off main (client) logic\n            [((AppDelegate*)[[NSApplication sharedApplication] delegate]) completeInitialization:self.preferences];\n            \n            break;\n            \n        //support, yes!\n        case SUPPORT_YES:\n            \n            //open patreon URL\n            // invokes user's default browser\n            [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:PATREON_URL]];\n        \n            //fall thru as we want to close/set app state\n        \n        //support, no :(\n        case SUPPORT_NO:\n            \n            //close window\n            [self.window close];\n            \n            //finally set app's background/foreground state\n            [((AppDelegate*)[[NSApplication sharedApplication] delegate]) setActivationPolicy];\n            \n            break;\n            \n        default:\n            break;\n    }\n\n    return;\n}\n\n//show a view\n// note: replaces old view and highlights specified responder\n-(void)showView:(NSView*)view firstResponder:(NSInteger)firstResponder\n{\n    //x position\n    CGFloat xPos = 0;\n    \n    //y position\n    CGFloat yPos = 0;\n    \n    //not in dark mode?\n    // make window white\n    if(YES != isDarkMode())\n    {\n        //set white\n        view.layer.backgroundColor = [NSColor whiteColor].CGColor;\n    }\n    \n    //set content view size\n    self.window.contentSize = view.frame.size;\n    \n    //update config view\n    self.window.contentView = view;\n    \n    //center x\n    xPos = NSWidth(self.window.screen.frame)/2 - NSWidth(self.window.frame)/2;\n    \n    //center y\n    yPos = NSHeight(self.window.screen.frame)/2 - NSHeight(self.window.frame)/2;\n    \n    //center window\n    [self.window setFrame:NSMakeRect(xPos, yPos, NSWidth(self.window.frame), NSHeight(self.window.frame)) display:YES];\n\n    //make 'next' button first responder\n    // calling this without a timeout, sometimes fails :/\n    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (100 * NSEC_PER_MSEC)), dispatch_get_main_queue(), ^{\n        \n        //set first responder\n        if(-1 != firstResponder)\n        {\n            //first responder\n            [self.window makeFirstResponder:[view viewWithTag:firstResponder]];\n        }\n        \n    });\n\n    return;\n}\n\n@end\n"
  },
  {
    "path": "LuLu/App/XPCDaemonClient.h",
    "content": "//\n//  file: XPCDaemonClient.h\n//  project: lulu (shared)\n//  description: talk to daemon via XPC (header)\n//\n//  created by Patrick Wardle\n//  copyright (c) 2017 Objective-See. All rights reserved.\n//\n\n@import Foundation;\n\n#import \"XPCDaemonProto.h\"\n\n@interface XPCDaemonClient : NSObject\n{\n    \n}\n\n//xpc connection to daemon\n@property (atomic, strong, readwrite)NSXPCConnection* daemon;\n\n//get preferences\n// note: synchronous\n-(NSDictionary*)getPreferences;\n\n//update (save) preferences\n// note: synchronous, as then returns latest preferences\n-(NSDictionary*)updatePreferences:(NSDictionary*)preferences;\n\n//get rules\n// note: synchronous\n-(NSDictionary*)getRules;\n\n//add rule\n-(void)addRule:(NSDictionary*)info;\n\n//disable (or re-enable) rule\n-(void)toggleRule:(NSString*)key rule:(NSString*)uuid state:(NSNumber*)state;\n\n//delete rule\n-(void)deleteRule:(NSString*)key rule:(NSString*)uuid;\n\n//import rules\n-(BOOL)importRules:(NSData*)newRules userOnly:(BOOL)userOnly;\n\n//cleanup rules\n-(NSInteger)cleanupRules:(BOOL)full;\n\n//get current profile\n-(NSString*)getCurrentProfile;\n\n//get list of profiles\n-(NSMutableArray*)getProfiles;\n\n//set profile\n-(BOOL)setProfile:(NSString*)name;\n\n//add profile\n-(BOOL)addProfile:(NSString*)name preferences:(NSDictionary*)preferences;\n\n//delete profile\n-(BOOL)deleteProfile:(NSString*)name;\n\n//uninstall\n-(BOOL)uninstall;\n\n@end\n"
  },
  {
    "path": "LuLu/App/XPCDaemonClient.m",
    "content": "//\n//  file: XPCDaemonClient.m\n//  project: lulu (shared)\n//  description: talk to daemon via XPC (header)\n//\n//  created by Patrick Wardle\n//  copyright (c) 2017 Objective-See. All rights reserved.\n//\n\n#import \"consts.h\"\n#import \"XPCUser.h\"\n#import \"utilities.h\"\n#import \"AppDelegate.h\"\n#import \"XPCUserProto.h\"\n#import \"XPCDaemonClient.h\"\n\n/* GLOBALS */\n\n//log handle\nextern os_log_t logHandle;\n\n//alert (windows)\nextern NSMutableDictionary* alerts;\n\n@implementation XPCDaemonClient\n\n@synthesize daemon;\n\n//init\n// create XPC connection & set remote obj interface\n-(id)init\n{\n    //super\n    self = [super init];\n    if(nil != self)\n    {\n        //alloc/init\n        daemon = [[NSXPCConnection alloc] initWithMachServiceName:DAEMON_MACH_SERVICE options:0];\n    \n        //set remote object interface\n        self.daemon.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(XPCDaemonProtocol)];\n        \n        //set exported object interface (protocol)\n        self.daemon.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(XPCUserProtocol)];\n        \n        //set exported object\n        // this will allow daemon to invoke user methods!\n        self.daemon.exportedObject = [[XPCUser alloc] init];\n    \n        //resume\n        [self.daemon resume];\n    }\n    \n    return self;\n}\n\n//get preferences\n// note: synchronous, will block until daemon responds\n-(NSDictionary*)getPreferences\n{\n    //preferences\n    __block NSDictionary* preferences = nil;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"invoking daemon XPC method, '%s'\", __PRETTY_FUNCTION__);\n    \n    [[self.daemon synchronousRemoteObjectProxyWithErrorHandler:^(NSError * proxyError)\n    {\n          //err msg\n          os_log_error(logHandle, \"ERROR: failed to execute daemon XPC method '%s' (error: %{public}@)\", __PRETTY_FUNCTION__, proxyError);\n\n   }] getPreferences:^(NSDictionary* preferencesFromDaemon)\n   {\n       //dbg msg\n       os_log_debug(logHandle, \"got preferences: %{public}@\", preferencesFromDaemon);\n       \n       //save\n       preferences = preferencesFromDaemon;\n       \n   }];\n    \n    return preferences;\n}\n\n//update (save) preferences\n// note: will merge into current ones\n-(NSDictionary*)updatePreferences:(NSDictionary*)preferences\n{\n    //updated preferences (from daemon)\n    __block NSDictionary* updatedPreferences = nil;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"invoking daemon XPC method, '%s'\", __PRETTY_FUNCTION__);\n    \n    //update prefs\n    [[self.daemon synchronousRemoteObjectProxyWithErrorHandler:^(NSError * proxyError)\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: failed to execute daemon XPC method '%s' (error: %{public}@)\", __PRETTY_FUNCTION__, proxyError);\n          \n    }] updatePreferences:preferences reply:^(NSDictionary* preferences)\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"got preferences: %{public}@\", preferences);\n        \n        //save\n        updatedPreferences = preferences;\n        \n    }];\n    \n    return updatedPreferences;\n}\n\n//get rules\n// note: synchronous, will block until daemon responds\n-(NSDictionary*)getRules\n{\n    //rules\n    __block NSMutableDictionary* rules = nil;\n    \n    //error\n    __block NSError* error = nil;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"invoking daemon XPC method, '%s'\", __PRETTY_FUNCTION__);\n    \n    //make XPC request to get rules\n    [[self.daemon synchronousRemoteObjectProxyWithErrorHandler:^(NSError * proxyError)\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: failed to execute daemon XPC method '%s' (error: %{public}@)\", __PRETTY_FUNCTION__, proxyError);\n        \n    }] getRules:^(NSData* archivedRules)\n    {\n        //unarchive\n        rules = [NSKeyedUnarchiver unarchivedObjectOfClasses:\n                 [NSSet setWithArray: @[[NSMutableDictionary class], [NSMutableArray class], [NSString class], [NSNumber class], [NSMutableSet class], [NSDate class], [Rule class]]] fromData:archivedRules error:&error];\n        \n        if(nil != error)\n        {\n            //err msg\n            os_log_error(logHandle, \"ERROR: failed to unarchive rules: %{public}@\", error);\n        }\n    \n    }];\n    \n    return rules;\n}\n\n//add rule\n-(void)addRule:(NSDictionary*)info\n{\n    //dbg msg\n    os_log_debug(logHandle, \"invoking daemon XPC method, '%s' with info: %{public}@\", __PRETTY_FUNCTION__, info);\n    \n    //make XPC request to add rule\n    [[self.daemon synchronousRemoteObjectProxyWithErrorHandler:^(NSError * proxyError)\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: failed to execute daemon XPC method '%s' (error: %{public}@)\", __PRETTY_FUNCTION__, proxyError);\n        \n    }] addRule:info];\n    \n    return;\n}\n\n//disable (or re-enable) rule\n-(void)toggleRule:(NSString*)key rule:(NSString*)uuid state:(NSNumber*)state\n{\n    //dbg msg\n    os_log_debug(logHandle, \"invoking daemon XPC method, '%s' with key: %{public}@, rule id: %{public}@\", __PRETTY_FUNCTION__, key, uuid);\n    \n    //disable rule\n    [[self.daemon synchronousRemoteObjectProxyWithErrorHandler:^(NSError * proxyError)\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: failed to execute daemon XPC method '%s' (error: %{public}@)\", __PRETTY_FUNCTION__, proxyError);\n        \n    }] toggleRule:key rule:uuid state:state];\n    \n    return;\n}\n\n//delete rule\n-(void)deleteRule:(NSString*)key rule:(NSString*)uuid\n{\n    //dbg msg\n    os_log_debug(logHandle, \"invoking daemon XPC method, '%s' with key: %{public}@, rule id: %{public}@\", __PRETTY_FUNCTION__, key, uuid);\n    \n    //delete rule\n    [[self.daemon synchronousRemoteObjectProxyWithErrorHandler:^(NSError * proxyError)\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: failed to execute daemon XPC method '%s' (error: %{public}@)\", __PRETTY_FUNCTION__, proxyError);\n        \n    }] deleteRule:key rule:uuid];\n    \n    return;\n}\n\n//cleanup rules\n-(NSInteger)cleanupRules:(BOOL)full\n{\n    //result\n    __block NSInteger deletedRules = -1;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"invoking daemon XPC method, '%s'\", __PRETTY_FUNCTION__);\n    \n    //import rules\n    [[self.daemon synchronousRemoteObjectProxyWithErrorHandler:^(NSError * proxyError)\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: failed to execute daemon XPC method '%s' (error: %{public}@)\", __PRETTY_FUNCTION__, proxyError);\n          \n    }] cleanupRules:full reply:^(NSInteger result)\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"daemon XPC method, '%s', done! (returned %ld)\", __PRETTY_FUNCTION__, (long)deletedRules);\n         \n        //save result\n        deletedRules = result;\n         \n    }];\n    \n    return deletedRules;\n}\n\n//update (save) preferences\n-(BOOL)importRules:(NSData*)newRules userOnly:(BOOL)userOnly\n{\n    //flag\n    __block BOOL wasImported = NO;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"invoking daemon XPC method, '%s'\", __PRETTY_FUNCTION__);\n    \n    //import rules\n    [[self.daemon synchronousRemoteObjectProxyWithErrorHandler:^(NSError * proxyError)\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: failed to execute daemon XPC method '%s' (error: %{public}@)\", __PRETTY_FUNCTION__, proxyError);\n          \n    }] importRules:newRules userOnly:(BOOL)userOnly result:^(BOOL result)\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"daemon XPC method, '%s', done!\", __PRETTY_FUNCTION__);\n         \n        //set flag\n        wasImported = YES;\n         \n    }];\n    \n    return wasImported;\n}\n\n//get current profile\n-(NSString*)getCurrentProfile\n{\n    //rules\n    __block NSString* currentProfile = nil;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"invoking daemon XPC method, '%s'\", __PRETTY_FUNCTION__);\n    \n    //make XPC request to get profiles\n    [[self.daemon synchronousRemoteObjectProxyWithErrorHandler:^(NSError* proxyError)\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: failed to execute daemon XPC method '%s' (error: %{public}@)\", __PRETTY_FUNCTION__, proxyError);\n        \n    }] getCurrentProfile:^(NSString* currrentProfileFromDaemon)\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"current profile from daemon: '%{public}@'\", currrentProfileFromDaemon);\n        \n        //save\n        currentProfile = currrentProfileFromDaemon;\n    \n    }];\n    \n    return currentProfile;\n}\n\n//get list of profiles\n-(NSMutableArray*)getProfiles\n{\n    //rules\n    __block NSMutableArray* profiles = nil;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"invoking daemon XPC method, '%s'\", __PRETTY_FUNCTION__);\n    \n    //make XPC request to get profiles\n    [[self.daemon synchronousRemoteObjectProxyWithErrorHandler:^(NSError* proxyError)\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: failed to execute daemon XPC method '%s' (error: %{public}@)\", __PRETTY_FUNCTION__, proxyError);\n        \n    }] getProfiles:^(NSArray* profilesFromDaemon)\n    {\n        //save\n        profiles = [profilesFromDaemon mutableCopy];\n    \n    }];\n    \n    return profiles;\n}\n\n//set profile\n-(BOOL)setProfile:(NSString*)name\n{\n    //flag\n    __block BOOL wasSet = NO;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"invoking daemon XPC method, '%s' with name: %{public}@\", __PRETTY_FUNCTION__, name);\n    \n    //send XPC message to set profile\n    [[self.daemon synchronousRemoteObjectProxyWithErrorHandler:^(NSError* proxyError)\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: failed to execute daemon XPC method '%s' (error: %{public}@)\", __PRETTY_FUNCTION__, proxyError);\n        \n    }] setProfile:name reply:^(BOOL reply)\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"daemon XPC method, '%s', done!\", __PRETTY_FUNCTION__);\n          \n        //set flag\n        wasSet = reply;\n          \n    }];\n    \n    return wasSet;\n}\n\n//add profile\n-(BOOL)addProfile:(NSString*)name preferences:(NSDictionary*)preferences\n{\n    //flag\n    __block BOOL wasAdded = NO;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"invoking daemon XPC method, '%s' with %{public}@\", __PRETTY_FUNCTION__, name);\n    \n    //make XPC request to add profile\n    [[self.daemon synchronousRemoteObjectProxyWithErrorHandler:^(NSError* proxyError)\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: failed to execute daemon XPC method '%s' (error: %{public}@)\", __PRETTY_FUNCTION__, proxyError);\n        \n    }] addProfile:name preferences:preferences reply:^(BOOL reply)\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"daemon XPC method, '%s', done!\", __PRETTY_FUNCTION__);\n          \n        //set flag\n        wasAdded = reply;\n          \n    }];\n    \n    return wasAdded;\n}\n\n//delete profile\n-(BOOL)deleteProfile:(NSString*)name\n{\n    //flag\n    __block BOOL wasDeleted = NO;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"invoking daemon XPC method, '%s' with name: %{public}@\", __PRETTY_FUNCTION__, name);\n    \n    //send XPC message to delete profile\n    [[self.daemon synchronousRemoteObjectProxyWithErrorHandler:^(NSError* proxyError)\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: failed to execute daemon XPC method '%s' (error: %{public}@)\", __PRETTY_FUNCTION__, proxyError);\n        \n    }] deleteProfile:name reply:^(BOOL reply)\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"daemon XPC method, '%s', done!\", __PRETTY_FUNCTION__);\n         \n        //set flag\n        wasDeleted = reply;\n         \n    }];\n    \n    //dbg msg\n    os_log_debug(logHandle, \"daemon XPC method, '%s' with name: %{public}@ returned\", __PRETTY_FUNCTION__, name);\n    \n    return wasDeleted;\n}\n\n//uninstall\n-(BOOL)uninstall\n{\n    //flag\n    __block BOOL uninstalled = NO;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"invoking daemon XPC method, '%s'\", __PRETTY_FUNCTION__);\n    \n    //uninstall\n    [[self.daemon synchronousRemoteObjectProxyWithErrorHandler:^(NSError * proxyError)\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: failed to execute daemon XPC method '%s' (error: %{public}@)\", __PRETTY_FUNCTION__, proxyError);\n          \n    }] uninstall:^(BOOL result)\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"daemon XPC method, '%s', done!\", __PRETTY_FUNCTION__);\n        \n        //set flag\n        uninstalled = result;\n        \n    }];\n    \n    return uninstalled;\n\n}\n\n@end\n"
  },
  {
    "path": "LuLu/App/XPCUser.h",
    "content": "//\n//  file: XPCUser.h\n//  project: lulu (login item)\n//  description: user XPC methods (header)\n//\n//  created by Patrick Wardle\n//  copyright (c) 2018 Objective-See. All rights reserved.\n//\n\n@import OSLog;\n@import Foundation;\n\n#import \"XPCUserProto.h\"\n\n@interface XPCUser : NSObject <XPCUserProtocol>\n{\n    \n}\n\n@end\n"
  },
  {
    "path": "LuLu/App/XPCUser.m",
    "content": "//\n//  file: XPCUser.m\n//  project: lulu (login item)\n//  description: user XPC methods\n//\n//  created by Patrick Wardle\n//  copyright (c) 2018 Objective-See. All rights reserved.\n//\n\n#import \"consts.h\"\n#import \"XPCUser.h\"\n#import \"utilities.h\"\n#import \"AppDelegate.h\"\n#import \"AlertWindowController.h\"\n\n@implementation XPCUser\n\n/* GLOBALS */\n\n//log handle\nextern os_log_t logHandle;\n\n//alert (windows)\nextern NSMutableDictionary* alerts;\n\n//show an alert window\n-(void)alertShow:(NSDictionary*)alert reply:(void (^)(NSDictionary*))reply\n{\n    //dbg msg\n    os_log_debug(logHandle, \"daemon invoked user XPC method, '%s', with %{public}@\", __PRETTY_FUNCTION__, alert);\n    \n    //on main (ui) thread\n    dispatch_sync(dispatch_get_main_queue(), ^{\n        \n        //alert window\n        AlertWindowController* alertWindow = nil;\n        \n        //alloc/init alert window\n        alertWindow = [[AlertWindowController alloc] initWithWindowNibName:@\"AlertWindow\"];\n                \n        //sync to save alert\n        // ensures there is a (memory) reference to the window\n        @synchronized(alerts)\n        {\n            //save\n            alerts[alert[KEY_UUID]] = alertWindow;\n        }\n        \n        //set reply\n        alertWindow.reply = reply;\n        \n        //set alert\n        alertWindow.alert = alert;\n        \n        //show in all spaces\n        alertWindow.window.collectionBehavior = NSWindowCollectionBehaviorCanJoinAllSpaces;\n        \n        //show alert window\n        [alertWindow showWindow:self];\n    \n        //make alert window key\n        [alertWindow.window makeKeyAndOrderFront:self];\n        \n        //set app's background/foreground state\n        [((AppDelegate*)[[NSApplication sharedApplication] delegate]) setActivationPolicy];\n        \n        //request user attention\n        // bounces icon on the dock\n        [NSApp requestUserAttention:NSCriticalRequest];\n        \n        //delay, then make the alert window front\n        // note: this will stop the dock bouncing...\n        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{\n            \n            //activate\n            if(@available(macOS 14.0, *)) {\n                [NSApp activate];\n            }\n            else\n            {\n                [NSApp activateIgnoringOtherApps:YES];\n            }\n            \n            //make it modal(ish)\n            [alertWindow.window setLevel:NSPopUpMenuWindowLevel];\n            \n            //code sign change?\n            // show code signing popover\n            if(YES == [alert[KEY_CS_CHANGE] boolValue])\n            {\n                //dbg msg\n                os_log_debug(logHandle, \"code signing information changed, will show (modal) alert to user\");\n            \n                //invoke handler to open\n                [alertWindow openSigningInfoPopover];\n                \n                //show (modal) alert\n                dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{\n                    \n                    //lower window level (so alert can show above)\n                    [alertWindow.window setLevel:NSNormalWindowLevel];\n                    \n                    //alert\n                    showAlert(NSAlertStyleInformational, [NSString stringWithFormat:NSLocalizedString(@\"%@'s code signing information has changed\", @\"%@'s code signing information has changed\"), alert[KEY_PROCESS_NAME]], @\"\", @[NSLocalizedString(@\"OK\", @\"OK\")]);\n                    \n                    //(re)set window level\n                    [alertWindow.window setLevel:NSPopUpMenuWindowLevel];\n                    \n                });\n            }\n        });\n    });\n    \n    //reverse dns resolve ip\n    // background resolve, then update alert window\n    if(nil != alert[KEY_HOST])\n    {\n        //async\n        // resolve ip -> host\n        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{\n            \n            //responses\n            NSArray* responses = nil;\n            \n            //address\n            NSString* address = nil;\n            \n            //capture\n            address = alert[KEY_HOST];\n            \n            //resolve\n            responses = resolveAddress(address);\n            \n            //dbg msg\n            os_log_debug(logHandle, \"resolved %{public}@ to %{public}@\", address, responses);\n         \n            //sync to add to alert window(s)\n            @synchronized(alerts)\n            {\n                //find any who's ip matches\n                [alerts enumerateKeysAndObjectsUsingBlock:^(id key, AlertWindowController* alertWindow, BOOL* stop) {\n                  \n                    //match?\n                    // update alert window\n                    if(YES == [alertWindow.alert[KEY_HOST] isEqualToString:address])\n                    {\n                        //update window on main thread\n                        dispatch_async(dispatch_get_main_queue(), ^{\n                            \n                            //response\n                            NSString* response = nil;\n                            \n                            //set\n                            response = responses.firstObject;\n                            \n                            //error/not found?\n                            if(0 == response.length)\n                            {\n                                //set default\n                                response = NSLocalizedString(@\"unknown\", @\"unknown\");\n                            }\n                            \n                            //set text\n                            alertWindow.reverseDNS.string = response;\n                            \n                            //wrapping\n                            [alertWindow setWrapping:alertWindow.reverseDNS];\n                            \n                            //set tooltip\n                            alertWindow.reverseDNS.toolTip = [NSString stringWithFormat:NSLocalizedString(@\"Reverse Domain: %@\", @\"Reverse Domain %@\"), alertWindow.reverseDNS.string];\n                        });\n                    }\n                }];\n            }\n        });\n    }\n    \n    return;\n}\n\n//rule changed\n// broadcast new rules, so any (relevant) windows can be updated\n-(void)rulesChanged\n{\n    //dbg msg\n    os_log_debug(logHandle, \"daemon invoked user XPC method, '%s'\", __PRETTY_FUNCTION__);\n    \n    //broadcast\n    [[NSNotificationCenter defaultCenter] postNotificationName:RULES_CHANGED object:nil userInfo:nil];\n    \n    return;\n}\n\n@end\n"
  },
  {
    "path": "LuLu/App/main.m",
    "content": "//\n//  main.m\n//  LuLu\n//\n//  Created by Patrick Wardle on 8/1/20.\n//  Copyright (c) 2020 Objective-See. All rights reserved.\n//\n\n#import \"consts.h\"\n#import \"utilities.h\"\n#import \"Configure.h\"\n\n@import Cocoa;\n@import OSLog;\n\n//TODO:\n// new pref: allow apple programs, unless has args + parent is untrusted\n// add rule option: args\n\n/* GLOBALS */\n\n//log handle\nos_log_t logHandle = nil;\n\nint main(int argc, const char * argv[]) {\n    \n    //status\n    int status = -1;\n    \n    //config obj\n    Configure* configure = nil;\n    \n    //pool\n    @autoreleasepool {\n        \n        //init log\n        logHandle = os_log_create(BUNDLE_ID, \"application\");\n        \n        //dbg msg(s)\n        os_log_debug(logHandle, \"started: %{public}@ (pid: %d / uid: %d)\", NSProcessInfo.processInfo.arguments.firstObject, getpid(), getuid());\n        os_log_debug(logHandle, \"arguments: %{public}@\", NSProcessInfo.processInfo.arguments);\n    \n        /* cmdline interface - for install/upgrade/uninstall */\n        \n        //install?\n        if(YES == [NSProcessInfo.processInfo.arguments containsObject:@\"-install\"])\n        {\n            //first check root\n            if(0 != geteuid())\n            {\n                //err msg\n                printf(\"\\nLULU ERROR: cmdline interface actions require root\\n\\n\");\n                goto bail;\n            }\n            \n            //init\n            configure = [[Configure alloc] init];\n            \n            //dbg msg\n            os_log_debug(logHandle, \"performing cmdline install\");\n            \n            //install\n            if(YES != [configure install])\n            {\n                //error\n                printf(\"\\nLULU ERROR: install failed (see system log for details)\\n\\n\");\n                goto bail;\n            }\n            \n            //dbg msg\n            printf(\"\\nLULU: installed\\n\\n\");\n            \n            //done\n            goto bail;\n        }\n        \n        //upgrade?\n        else if(YES == [NSProcessInfo.processInfo.arguments containsObject:@\"-upgrade\"])\n        {\n            //first check root\n            if(0 != geteuid())\n            {\n                //err msg\n                printf(\"\\nLULU ERROR: cmdline interface actions require root\\n\\n\");\n                goto bail;\n            }\n            \n            //init\n            configure = [[Configure alloc] init];\n            \n            //dbg msg\n            os_log_debug(logHandle, \"performing cmdline upgrade\");\n            \n            //upgrade\n            if(YES != [configure upgrade])\n            {\n                //error\n                printf(\"\\nLULU ERROR: upgrade failed (see system log for details)\\n\\n\");\n                goto bail;\n            }\n            \n            //dbg msg\n            printf(\"\\nLULU: upgraded\\n\\n\");\n            \n            //done\n            goto bail;\n        }\n        \n        //uninstall?\n        if(YES == [NSProcessInfo.processInfo.arguments containsObject:@\"-uninstall\"])\n        {\n            //first check root\n            if(0 != geteuid())\n            {\n                //err msg\n                printf(\"\\nLULU ERROR: cmdline interface actions require root\\n\\n\");\n                goto bail;\n            }\n            \n            //init\n            configure = [[Configure alloc] init];\n            \n            //dbg msg\n            os_log_debug(logHandle, \"performing cmdline uninstall\");\n            \n            //uninstall\n            if(YES != [configure uninstall])\n            {\n                //error\n                printf(\"\\nLULU ERROR: uninstall failed (see system log for details)\\n\\n\");\n                goto bail;\n            }\n            \n            //dbg msg\n            printf(\"\\nLULU: uninstalled\\n\\n\");\n            \n            //done\n            goto bail;\n        }\n        \n        //quit?\n        // this is the copy, to (just) deactivate extension\n        if(YES == [NSProcessInfo.processInfo.arguments containsObject:@\"-quit\"])\n        {\n            //init\n            configure = [[Configure alloc] init];\n            \n            //dbg msg\n            os_log_debug(logHandle, \"performing cmdline quit\");\n            \n            //quit\n            [configure quit];\n            \n            //done\n            goto bail;\n        }\n        \n        //invalid args\n        // just print msg, for cmdline case\n        else if(NSProcessInfo.processInfo.arguments.count > 1)\n        {\n            //err msg\n            printf(\"\\nLULU ERROR: %s are not valid args\\n\\n\", NSProcessInfo.processInfo.arguments.description.UTF8String);\n        }\n    \n        //main app interface\n        status = NSApplicationMain(argc, argv);\n        \n    } //pool\n    \nbail:\n    \n    return status;\n}\n"
  },
  {
    "path": "LuLu/App/mul.lproj/AboutWindow.xcstrings",
    "content": "{\n  \"sourceLanguage\" : \"en\",\n  \"strings\" : {\n    \"6g3-Pg-x3P.title\" : {\n      \"comment\" : \"Class = \\\"NSButtonCell\\\"; title = \\\"Support Us!\\\"; ObjectID = \\\"6g3-Pg-x3P\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Unterstütze uns!\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Support Us!\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"¡Apóyanos!\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Soutenez nous !\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sostienici!\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"저희를 응원해 주세요!\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wesprzyj nas!\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Suporte-nos!\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bizi Destekleyin!\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Підтримайте нас!\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ہماری حمایت کریں!\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"支持我们！\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"支持我們！\"\n          }\n        }\n      }\n    },\n    \"bBK-v0-ypq.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"Version:\\\"; ObjectID = \\\"bBK-v0-ypq\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Version:\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Version:\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Versión:\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Version : \"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Versione:\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"버전:\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wersja:\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Versão:\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sürüm:\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Версія:\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ورژن:\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"版本：\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"版本：\"\n          }\n        }\n      }\n    },\n    \"fJg-qw-wDf.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"Patrons & Friends\\\"; ObjectID = \\\"fJg-qw-wDf\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Unterstützer & Freunde:\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Patrons & Friends\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Patrons & Friends\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mécènes et amis\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sostenitori e Amici\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Patron 후원자 & 친구들\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Patroni i Przyjaciele\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Patrocinadores e Amigos\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aboneler ve Arkadaşlar\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Патрони і друзі\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"سرپرست اور دوست\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"赞助者&伙伴\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"贊助者 & 朋友\"\n          }\n        }\n      }\n    },\n    \"J9x-sM-h9S.title\" : {\n      \"comment\" : \"Class = \\\"NSButtonCell\\\"; title = \\\"More Information\\\"; ObjectID = \\\"J9x-sM-h9S\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Weitere Informationen\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"More Information\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Más Información\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Plus d’information\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Maggiori informazioni\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"더 많은 정보\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Więcej informacji\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mais Informações\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Daha Fazla Bilgi\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Більше інформації\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"مزید معلومات\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"更多资讯\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"更多資訊\"\n          }\n        }\n      }\n    }\n  },\n  \"version\" : \"1.0\"\n}"
  },
  {
    "path": "LuLu/App/mul.lproj/AddRule.xcstrings",
    "content": "{\n  \"sourceLanguage\" : \"en\",\n  \"strings\" : {\n    \"5ic-Om-d8g.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"Remote port\\\"; ObjectID = \\\"5ic-Om-d8g\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Remote Port\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Remote port\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Puerto remoto\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Port distant\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Porta remota\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"원격 포트\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zdalny port\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Porta remota\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Uzak kapı\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Віддалений порт\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ریموٹ پورٹ\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"远程端口\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"遠端連接埠\"\n          }\n        }\n      }\n    },\n    \"7yf-wW-FZC.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"Remote address/domain\\\"; ObjectID = \\\"7yf-wW-FZC\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Remote Adresse/Domain\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Remote address/domain\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dirección remota/dominio\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Adresse/domaine distant\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Indirizzo/Dominio remoto\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"원격 주소/도메인\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zdalny adres/domena\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Endereço/domínio remoto\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Uzak adres/Etki alanı\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Віддалена адреса/домен\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ریموٹ ایڈریس/ڈومین\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"远程地址/域\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"遠端位址／網域\"\n          }\n        }\n      }\n    },\n    \"F0z-JX-Cv5.title\" : {\n      \"comment\" : \"Class = \\\"NSWindow\\\"; title = \\\"Add Rule (for outgoing connections)\\\"; ObjectID = \\\"F0z-JX-Cv5\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Regel hinzufügen (für ausgehende Verbidungen)\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Add Rule (for outgoing connections)\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Agregar Regla (para conexiones salientes)\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ajouter une règle (pour connections sortantes)\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aggiungi regola (per connessioni in uscita)\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"규칙 추가 (나가는 연결)\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dodaj regułę (dla połączeń wychodzących)\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Adicionar regra (para conexões de saída)\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kural Ekle (Dışarı Giden Bağlantılar)\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Додати правило (для вихідних з'єднань)\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"قانون شامل کریں (باہر جانے والے کنکشنز کے لیے)\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"新增规则（适用对外链接）\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"新增規則（適用於對外連線）\"\n          }\n        }\n      }\n    },\n    \"FCA-Cv-yT3.title\" : {\n      \"comment\" : \"Class = \\\"NSButtonCell\\\"; title = \\\"regex?\\\"; ObjectID = \\\"FCA-Cv-yT3\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"regex?\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"regex?\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"regex?\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"regex ?\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"정규 표현식?\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"regex?\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"expressão regular?\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Düzenli ifade\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"regex?\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ریگولر ایکسپریشن؟\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"正则表达式\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"正規表達式？\"\n          }\n        }\n      },\n      \"shouldTranslate\" : false\n    },\n    \"fX0-Jq-Okq.title\" : {\n      \"comment\" : \"Class = \\\"NSButtonCell\\\"; title = \\\"Cancel\\\"; ObjectID = \\\"fX0-Jq-Okq\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Abbrechen\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Cancel\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cancelar\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Annuler\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Annulla\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"취소\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Anuluj\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cancelar\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vazgeç\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Скасувати\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"منسوخ کریں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"取消\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"取消\"\n          }\n        }\n      }\n    },\n    \"JJl-Lz-apr.title\" : {\n      \"comment\" : \"Class = \\\"NSButtonCell\\\"; title = \\\" Block\\\"; ObjectID = \\\"JJl-Lz-apr\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \" Blockieren\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \" Block\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bloquear\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bloquer\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \" Blocca\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \" 차단\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Blokuj\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bloquear\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Engelle\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Блокувати\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"بلاک کریں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"阻止\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"阻擋\"\n          }\n        }\n      }\n    },\n    \"kXW-Xv-Fc4.placeholderString\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; placeholderString = \\\"*\\\"; ObjectID = \\\"kXW-Xv-Fc4\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"*\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"*\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"*\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"*\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"*\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"*\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"*\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"*\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"*\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"*\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"*\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"*\"\n          }\n        }\n      },\n      \"shouldTranslate\" : false\n    },\n    \"oCK-aR-Ek4.title\" : {\n      \"comment\" : \"Class = \\\"NSButtonCell\\\"; title = \\\" Allow\\\"; ObjectID = \\\"oCK-aR-Ek4\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \" Erlauben\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \" Allow\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Permitir\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Autoriser\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \" Consenti\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \" 허용\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pozwól\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Permitir\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"İzin Ver\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Дозволити\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"اجازت دیں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"允许\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"允許\"\n          }\n        }\n      }\n    },\n    \"OoX-aE-Hgf.title\" : {\n      \"comment\" : \"Class = \\\"NSButtonCell\\\"; title = \\\"Browse\\\"; ObjectID = \\\"OoX-aE-Hgf\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Durchsuchen\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Browse\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Navegar\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Parcourir\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sfoglia\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"찾아보기\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Przeglądaj\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Buscar\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Göz At\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Огляд\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تلاش کریں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"浏览\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"瀏覽\"\n          }\n        }\n      }\n    },\n    \"QWe-2U-lfn.placeholderString\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; placeholderString = \\\"*\\\"; ObjectID = \\\"QWe-2U-lfn\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"*\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"*\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"*\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"*\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"*\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"*\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"*\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"*\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"*\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"*\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"*\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"*\"\n          }\n        }\n      },\n      \"shouldTranslate\" : false\n    },\n    \"tc1-pS-Wns.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"Program path\\\"; ObjectID = \\\"tc1-pS-Wns\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Programmpfad\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Program path\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ruta del programa\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Chemin du programme\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Percorso programma\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"프로그램 경로\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ścieżka programu\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Caminho do programa\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Program yolu\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Шлях до програми\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"پروگرام پاتھ\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"程序路径\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"程式路徑\"\n          }\n        }\n      }\n    },\n    \"V5P-DF-wCP.title\" : {\n      \"comment\" : \"Class = \\\"NSButtonCell\\\"; title = \\\"Add\\\"; ObjectID = \\\"V5P-DF-wCP\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hinzufügen\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Add\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Agregar\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ajouter\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aggiungi\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"추가\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dodaj\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Adicionar\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ekle\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Додати\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"اضافہ کریں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"新增\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"新增\"\n          }\n        }\n      }\n    }\n  },\n  \"version\" : \"1.0\"\n}"
  },
  {
    "path": "LuLu/App/mul.lproj/AlertWindow.xcstrings",
    "content": "{\n  \"sourceLanguage\" : \"en\",\n  \"strings\" : {\n    \"1zg-95-QM7.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\" -\\\"; ObjectID = \\\"1zg-95-QM7\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \" - Zertifizierungsinstanz 2\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \" -\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"- autorización de firma 2\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \" - autorité de signature 2\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \" - 인증 기관 2\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"- podpisanie autoryzacji 2\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"- imzalama otoritesi 2\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \" - سرٹیفیکیشن اتھارٹی 2\"\n          }\n        }\n      },\n      \"shouldTranslate\" : false\n    },\n    \"8eV-Ag-i7n.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"Connection:\\\"; ObjectID = \\\"8eV-Ag-i7n\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Verbindungen:\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Connection:\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Conexión:\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Connection : \"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Connessione:\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"연결:\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Połączenie:\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Conexão:\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bağlantı:\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"З'єднання:\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"کنکشن:\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"链接内容：\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"連線：\"\n          }\n        }\n      }\n    },\n    \"9OD-rL-0J2.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"Rule Duration:\\\"; ObjectID = \\\"9OD-rL-0J2\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Regeldauer:\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Rule Duration:\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Duración de la Regla:\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Durée de la règle : \"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Durata regola:\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"규칙 지속 시간:\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Czas trwania reguły:\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Duração da Regra:\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kural süresi:\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Тривалість правила:\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"قانون کی مدت:\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"规则持续时间：\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"規則持續時間：\"\n          }\n        }\n      }\n    },\n    \"31V-e4-dgv.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"port/protocol:\\\"; ObjectID = \\\"31V-e4-dgv\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Port/Protokoll:\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"port/protocol:\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"puerto/proto:\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"port/protocole : \"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"porta/protocollo:\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"포트/프로토콜:\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"port/protokół:\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"porta/protocolo:\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"kapı/protokol\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"порт/протокол:\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"پورٹ/پروٹوکول:\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"端口/通讯协议\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"連接埠／通訊協定：\"\n          }\n        }\n      }\n    },\n    \"80z-6q-eWC.title\" : {\n      \"comment\" : \"Class = \\\"NSButtonCell\\\"; title = \\\"Process lifetime\\\"; ObjectID = \\\"80z-6q-eWC\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Prozesslaufzeit\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Process lifetime\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Duración del proceso\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Durée de vie du processus\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Durata processo\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"프로세스 수명 동안\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Czas życia procesu\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Duração do processo:\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"İşlem yaşam süresi boyunca\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Тривалість життя процесу\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"عمل کی مدت\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"持续到进程结束\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"持續到此 process 結束\"\n          }\n        }\n      }\n    },\n    \"abH-g6-95w.placeholderString\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; placeholderString = \\\"HH\\\"; ObjectID = \\\"abH-g6-95w\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"HH:mm\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"HH\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"HH:mm\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"HH:mm\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"HH:mm\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"HH:mm\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"HH:mm\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"SS:dd\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"ГГ:хх\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"HH:mm\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"HH:mm\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"HH:mm\"\n          }\n        }\n      },\n      \"shouldTranslate\" : false\n    },\n    \"AuV-oM-p6G.placeholderString\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; placeholderString = \\\"mm\\\"; ObjectID = \\\"AuV-oM-p6G\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"mm\"\n          }\n        }\n      },\n      \"shouldTranslate\" : false\n    },\n    \"b63-At-csb.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"Details:\\\"; ObjectID = \\\"b63-At-csb\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Details:\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Details:\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Detalles:\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Détails : \"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dettagli:\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"세부 사항:\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Szczegóły:\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Detalhes:\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ayrıntılar:\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Деталі:\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تفصیلات:\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"详情：\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"詳細資訊\"\n          }\n        }\n      }\n    },\n    \"cUm-e3-Dh5.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\":\\\"; ObjectID = \\\"cUm-e3-Dh5\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \":\"\n          }\n        }\n      },\n      \"shouldTranslate\" : false\n    },\n    \"D1C-aK-AFU.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"Signing Authorities:\\\"; ObjectID = \\\"D1C-aK-AFU\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zertifizierungsinstanzen:\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Signing Authorities:\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Autorizaciones de Firma:\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Autorités de signature : \"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Autorità di firma:\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"인증 기관:\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Uwierzytelnianie podpisów:\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Assinaturas de Autorizações:\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"İmzalama otoriteleri:\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Довірені підписанти:\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"سرٹیفیکیشن اتھارٹیز:\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"签名机构：\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"簽署單位\"\n          }\n        }\n      }\n    },\n    \"F0z-JX-Cv5.title\" : {\n      \"comment\" : \"Class = \\\"NSWindow\\\"; title = \\\"LuLu Alert\\\"; ObjectID = \\\"F0z-JX-Cv5\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu Mitteilung\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"LuLu Alert\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Alerta de LuLu\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Alert LuLu\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Avviso LuLu\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu 경고\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Alert LuLu\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Alerta LuLu\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu İkâzı\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Сповіщення LuLu\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu الارٹ\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu警告\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu 警告\"\n          }\n        }\n      }\n    },\n    \"FLb-1c-otA.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\" -\\\"; ObjectID = \\\"FLb-1c-otA\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \" - Zertifizierungsinstanz 3\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \" -\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"- autorización de firma 3\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \" - autorité de signature 3\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \" - 인증 기관 3\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"- podpisanie autoryzacji 3\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"- imzalama otoritesi 3\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \" - سرٹیفیکیشن اتھارٹی 3\"\n          }\n        }\n      },\n      \"shouldTranslate\" : false\n    },\n    \"Fxr-aW-bT2.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"(reverse) dns:\\\"; ObjectID = \\\"Fxr-aW-bT2\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"(Reverse) DNS: \"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"(reverse) dns:\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"dns (inverso):\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"dns (inverse) : \"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"DNS inverso:\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"(역방향) DNS:\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"(reverse) dns:\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"DNS (reverso):\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"(ters) dns:\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"(зворотний) DNS:\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"(ریورس) ڈی این ایس:\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"（反向）DNS：\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"（反向）DNS：\"\n          }\n        }\n      }\n    },\n    \"FYF-6N-pro.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"Details & Options\\\"; ObjectID = \\\"FYF-6N-pro\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Details & Optionen\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Details & Options\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Detalles & Opciones\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Détails et options\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dettagli e opzioni\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"세부 사항 & 옵션\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Szczegóły i opcje\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Detalhes e Opções\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ayrıntılar ve Seçenekler\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Деталі та параметри\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تفصیلات اور آپشنز\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"详情&选项\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"詳細資訊 & 選項\"\n          }\n        }\n      }\n    },\n    \"G2Q-QQ-EX7.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"Rule Scope:\\\"; ObjectID = \\\"G2Q-QQ-EX7\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Regel-Geltungsbereich:\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Rule Scope:\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Alcance de la regla:\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Champ d’application de la règle : \"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dettagli e opzioni\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"규칙 적용 범위:\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zakres reguły:\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Alcance da Regra:\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kural kapsamı:\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Межі правила:\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"قانون کا دائرہ کار:\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"规则作用范围：\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"規則範圍\"\n          }\n        }\n      }\n    },\n    \"Gqr-cR-TAF.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"path:\\\"; ObjectID = \\\"Gqr-cR-TAF\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pfad:\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"path:\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ruta:\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"chemin : \"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"percorso:\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"경로:\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ścieżka:\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"caminho:\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"yol:\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"шлях:\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"پاتھ:\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"路径：\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"路徑：\"\n          }\n        }\n      }\n    },\n    \"HZu-Op-XHi.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"pid:\\\"; ObjectID = \\\"HZu-Op-XHi\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"pid:\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"pid:\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"pid:\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"pid : \"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"pid:\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"pid:\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"pid:\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"pid:\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"PID:\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"پی آئی ڈی:\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"pid：\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"pid:\"\n          }\n        }\n      },\n      \"shouldTranslate\" : false\n    },\n    \"Iys-aY-OZ4.title\" : {\n      \"comment\" : \"Class = \\\"NSMenuItem\\\"; title = \\\"Process\\\"; ObjectID = \\\"Iys-aY-OZ4\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Prozess\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Process\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Proceso\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Processus\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Processo\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"프로세스\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Proces\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Processo\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"İşlem\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Процес\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"عمل\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"进程\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Process\"\n          }\n        }\n      }\n    },\n    \"JEi-1U-vkU.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"Process Name\\\"; ObjectID = \\\"JEi-1U-vkU\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Prozessname\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Process Name\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nombre del Proceso\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nom du processus\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nome processo\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"프로세스 이름\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nazwa procesu\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nome do Processo\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"İşlem Adı\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Назва процесу\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"عمل کا نام\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"进程名称\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Process 名稱\"\n          }\n        }\n      }\n    },\n    \"JFW-5C-nvy.headerCell.title\" : {\n      \"comment\" : \"Class = \\\"NSTableColumn\\\"; headerCell.title = \\\"Name\\\"; ObjectID = \\\"JFW-5C-nvy\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Name\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Name\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nombre\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nom\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nome\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"이름\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nazwa\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nome\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ad\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Назва\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"نام\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"名称\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"名稱\"\n          }\n        }\n      }\n    },\n    \"Ki9-ld-5Xu.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\" -\\\"; ObjectID = \\\"Ki9-ld-5Xu\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \" - Zertifizierungsinstanz 1\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \" -\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"- autorización de firma 1\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \" - autorité de signature 1\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \" - 인증 기관 1\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"- podpisanie autoryzacji 1\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"- imzalama otoritesi 1\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \" - سرٹیفیکیشن اتھارٹی 1\"\n          }\n        }\n      },\n      \"shouldTranslate\" : false\n    },\n    \"N6E-eT-Q39.title\" : {\n      \"comment\" : \"Class = \\\"NSMenuItem\\\"; title = \\\"Remote Endpoint\\\"; ObjectID = \\\"N6E-eT-Q39\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Remote-Endpunkt\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Remote Endpoint\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Endpoint Remoto\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Point d’accès distant\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Endpoint remoto\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"원격 엔드포인트\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zdalny punkt końcowy\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Endpoint remote\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Uzak Bitiş Noktası\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Віддалена веб- або IP-адреса\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ریموٹ اینڈ پوائنٹ\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"远程端点\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"遠端端點\"\n          }\n        }\n      }\n    },\n    \"Pp2-2W-YkT.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"Process:\\\"; ObjectID = \\\"Pp2-2W-YkT\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Prozess:\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Process:\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Proceso:\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Processus : \"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Processo:\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"프로세스:\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Proces:\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Processo:\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"İşlem:\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Процес:\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"عمل:\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"进程：\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Process:\"\n          }\n        }\n      }\n    },\n    \"Ssw-3u-wEC.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"message\\\"; ObjectID = \\\"Ssw-3u-wEC\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nachricht\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"message\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"mensaje\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"message\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"messaggio\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"메시지\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"wiadomość\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"mensagem\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mesaj\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"повідомлення\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"پیغام\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"信息\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"訊息\"\n          }\n        }\n      }\n    },\n    \"T20-eE-vRR.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"args:\\\"; ObjectID = \\\"T20-eE-vRR\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Argumente:\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"args:\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"args:\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"arguments : \"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"argomenti:\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"인수:\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"argumenty:\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"argumentos:\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"argümanlar:\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"аргументи:\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ارجومنٹس:\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"参数：\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"參數：\"\n          }\n        }\n      }\n    },\n    \"Ubf-5c-Fd2.title\" : {\n      \"comment\" : \"Class = \\\"NSButtonCell\\\"; title = \\\"Always\\\"; ObjectID = \\\"Ubf-5c-Fd2\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Immer\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Always\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Siempre\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Toujours\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sempre\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"항상\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zawsze\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sempre\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Her zaman\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Завжди\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ہمیشہ\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"总是\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"總是\"\n          }\n        }\n      }\n    },\n    \"vmZ-KS-uuK.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"ip address:\\\"; ObjectID = \\\"vmZ-KS-uuK\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"IP-Adresse:\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"ip address:\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"dirección ip:\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"adresse ip : \"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"indirizzo IP:\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"IP 주소:\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"adres IP:\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"endereço de ip:\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ip adresi:\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"IP-адреса\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"آئی پی پتہ:\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"IP地址：\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"IP 位址：\"\n          }\n        }\n      }\n    },\n    \"W18-Ba-X7J.title\" : {\n      \"comment\" : \"Class = \\\"NSButtonCell\\\"; title = \\\"Block\\\"; ObjectID = \\\"W18-Ba-X7J\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Blockieren\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Block\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bloquear\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bloquer\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Blocca\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"차단\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Blokuj\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bloquear\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Engelle\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Блокувати\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"بلاک کریں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"阻止\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"阻擋\"\n          }\n        }\n      }\n    },\n    \"Wn5-T5-boq.title\" : {\n      \"comment\" : \"Class = \\\"NSButtonCell\\\"; title = \\\"Expires in:\\\"; ObjectID = \\\"Wn5-T5-boq\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Läuft ab in:\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Expires in:\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Expira en:\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Expire dans :\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scade tra:\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"만료까지:\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wygasa za:\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Expira em:\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Süre dolmasına:\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Закінчується через:\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"میعاد ختم ہونے میں:\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"过期时间：\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"過期時間：\"\n          }\n        }\n      }\n    },\n    \"ybM-PR-IbA.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"Time stamp: \\\"; ObjectID = \\\"ybM-PR-IbA\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zeitstempel:\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Time stamp: \"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Marca de tiempo:\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Horodatage : \"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Marca temporale:\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"타임 스탬프:\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sygnatura czasowa:\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Registro da hora:\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zaman damgası:\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Мітка часу:\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ٹائم اسٹیمپ:\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"時間戳：\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"時間戳：\"\n          }\n        }\n      }\n    },\n    \"Zk5-p6-VV3.title\" : {\n      \"comment\" : \"Class = \\\"NSButtonCell\\\"; title = \\\"Allow\\\"; ObjectID = \\\"Zk5-p6-VV3\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Erlauben\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Allow\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Permitir\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Autoriser\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Consenti\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"허용\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pozwól\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Permitir\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"İzin Ver\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Дозволити\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"اجازت دیں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"允许\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"允許\"\n          }\n        }\n      }\n    }\n  },\n  \"version\" : \"1.0\"\n}"
  },
  {
    "path": "LuLu/App/mul.lproj/ItemPaths.xcstrings",
    "content": "{\n  \"sourceLanguage\" : \"en\",\n  \"strings\" : {\n    \"NhE-Zh-Scd.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"Path(s):\\\"; ObjectID = \\\"NhE-Zh-Scd\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pfad(e):\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Path(s):\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ruta(s):\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Chemin(s) : \"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Percorso/i:\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"경로:\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ścieżka(i):\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Caminho(s):\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Yollar:\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Шлях(и):\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"راستہ/راستے:\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"路径：\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"路徑：\"\n          }\n        }\n      }\n    },\n    \"ox8-oX-X3s.title\" : {\n      \"comment\" : \"Class = \\\"NSButtonCell\\\"; title = \\\"Close\\\"; ObjectID = \\\"ox8-oX-X3s\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Schließen\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Close\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cerrar\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Fermer\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Chiudi\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"닫기\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zamknij\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Fechar\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kapat\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Закрити\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"بند کریں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"关闭\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"關閉\"\n          }\n        }\n      }\n    }\n  },\n  \"version\" : \"1.0\"\n}"
  },
  {
    "path": "LuLu/App/mul.lproj/MainMenu.xcstrings",
    "content": "{\n  \"sourceLanguage\" : \"en\",\n  \"strings\" : {\n    \"0Y1-Pq-6Fc.title\" : {\n      \"comment\" : \"Class = \\\"NSMenuItem\\\"; title = \\\"Show...\\\"; ObjectID = \\\"0Y1-Pq-6Fc\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Anzeigen…\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Show...\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mostrar...\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Afficher…\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mostra…\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"보이기...\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pokaż…\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mostrar...\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Göster…\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Показати…\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"دکھائیں...\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"显示…\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"顯示...\"\n          }\n        }\n      }\n    },\n    \"1HU-j3-Oa3.title\" : {\n      \"comment\" : \"Class = \\\"NSMenu\\\"; title = \\\"Switch\\\"; ObjectID = \\\"1HU-j3-Oa3\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wechseln\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Switch\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cambiar\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Basculer\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cambia\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"전환\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Przełącz\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Alternar\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Değiştir\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Перемкнути\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تبدیل کریں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"切换\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"切換\"\n          }\n        }\n      }\n    },\n    \"4Uv-rm-VzQ.title\" : {\n      \"comment\" : \"Class = \\\"NSMenuItem\\\"; title = \\\"Settings...\\\"; ObjectID = \\\"4Uv-rm-VzQ\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Einstellungen…\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Settings...\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configuración...\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Réglages…\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Impostazioni…\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"설정...\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ustawienia...\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configurações…\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ayarlar…\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Параметри…\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ترتیبات...\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"设置…\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"設定…\"\n          }\n        }\n      }\n    },\n    \"7kG-TA-f15.title\" : {\n      \"comment\" : \"Class = \\\"NSMenuItem\\\"; title = \\\"Profiles\\\"; ObjectID = \\\"7kG-TA-f15\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profile\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Profiles\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Perfiles\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profils\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profili\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"프로필\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profile\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Perfis\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profiller\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Профілі\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"پروفائلز\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"配置文件\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"設定檔\"\n          }\n        }\n      }\n    },\n    \"39l-3u-dUR.title\" : {\n      \"comment\" : \"Class = \\\"NSMenuItem\\\"; title = \\\"Import...\\\"; ObjectID = \\\"39l-3u-dUR\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Importieren…\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Import...\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Importar...\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Importer…\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Importa…\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"가져오기...\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Import...\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Importar…\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"İçe Aktar…\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Імпортувати…\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"درآمد کریں...\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"导入…\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"匯入...\"\n          }\n        }\n      }\n    },\n    \"ahR-T8-occ.title\" : {\n      \"comment\" : \"Class = \\\"NSMenuItem\\\"; title = \\\"Switch\\\"; ObjectID = \\\"ahR-T8-occ\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wechseln\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Switch\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cambiar\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Basculer\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cambia\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"전환\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Przełącz\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Alternar\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Değiştir\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Перемкнути\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تبدیل کریں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"切换\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"切換\"\n          }\n        }\n      }\n    },\n    \"aJV-EX-6bj.title\" : {\n      \"comment\" : \"Class = \\\"NSMenuItem\\\"; title = \\\"LuLu\\\"; ObjectID = \\\"aJV-EX-6bj\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"LuLu\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"لولو\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu\"\n          }\n        }\n      },\n      \"shouldTranslate\" : false\n    },\n    \"aZa-10-Ir1.title\" : {\n      \"comment\" : \"Class = \\\"NSMenuItem\\\"; title = \\\"Export...\\\"; ObjectID = \\\"aZa-10-Ir1\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Exportieren…\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Export...\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Exportar...\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Exporter…\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Esporta…\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"내보내기...\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Eksport...\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Exportar…\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dışa Aktar…\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Експортувати…\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"برآمد کریں...\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"导出…\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"匯出...\"\n          }\n        }\n      }\n    },\n    \"d49-Ze-8oD.title\" : {\n      \"comment\" : \"Class = \\\"NSMenu\\\"; title = \\\"Profiles\\\"; ObjectID = \\\"d49-Ze-8oD\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profile\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Profiles\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Perfiles\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profils\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profili\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"프로필\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profile\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Perfis\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profiller\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Профілі\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"پروفائلز\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"配置文件\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"設定檔\"\n          }\n        }\n      }\n    },\n    \"DEa-wY-se7.title\" : {\n      \"comment\" : \"Class = \\\"NSMenuItem\\\"; title = \\\"Quit LuLu\\\"; ObjectID = \\\"DEa-wY-se7\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu beenden\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Quit LuLu\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cerrar LuLu\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Quitter LuLu\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Chiudi LuLu\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu 종료\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wyjdź z LuLu\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Fechar LuLu\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu'dan Çık\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Закрити LuLu\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"لولو کو ختم کریں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"关闭LuLu\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"關閉 LuLu\"\n          }\n        }\n      }\n    },\n    \"gXq-yc-QnA.title\" : {\n      \"comment\" : \"Class = \\\"NSMenuItem\\\"; title = \\\"Add...\\\"; ObjectID = \\\"gXq-yc-QnA\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hinzufügen…\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Add...\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Agregar...\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ajouter…\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aggiungi…\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"추가...\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dodaj…\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Adicionar...\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ekle…\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Додати…\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"اضافی کریں...\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"新增...\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"新增...\"\n          }\n        }\n      }\n    },\n    \"J1I-fS-R65.title\" : {\n      \"comment\" : \"Class = \\\"NSMenu\\\"; title = \\\"LuLu\\\"; ObjectID = \\\"J1I-fS-R65\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"LuLu\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"لولو\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu\"\n          }\n        }\n      },\n      \"shouldTranslate\" : false\n    },\n    \"K0B-xd-gGB.title\" : {\n      \"comment\" : \"Class = \\\"NSMenuItem\\\"; title = \\\"Support LuLu 💕\\\"; ObjectID = \\\"K0B-xd-gGB\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu unterstützen 💕\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Support LuLu 💕\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Apoyar LuLu 💕\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Soutenir LuLu 💕\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Supporta LuLu 💕\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu 지원하기 💕\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wspieraj LuLu 💕\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Apoiar LuLu 💕\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu'yu Destekle 💕\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Підтримати LuLu 💕\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"لولو کی حمایت کریں 💕\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"支持 LuLu 💕\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"支持 LuLu 💕\"\n          }\n        }\n      }\n    },\n    \"l9M-p8-kao.title\" : {\n      \"comment\" : \"Class = \\\"NSMenuItem\\\"; title = \\\"Disable\\\"; ObjectID = \\\"l9M-p8-kao\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Deaktivieren\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Disable\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Deshabilitar\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Désactiver\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Disattiva\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"비활성화\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wyłącz\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desabilitar\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Devre Dışı Bırak\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Вимкнути\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ناکار کریں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"禁用\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"停用\"\n          }\n        }\n      }\n    },\n    \"lns-C6-Aa5.title\" : {\n      \"comment\" : \"Class = \\\"NSMenuItem\\\"; title = \\\"Uninstall LuLu\\\"; ObjectID = \\\"lns-C6-Aa5\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu deinstallieren\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Uninstall LuLu\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desinstalar LuLu\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Désinstaller LuLu\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Disinstalla LuLu\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu 삭제\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Odinstaluj LuLu\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desinstalar LuLu\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu'yu Kaldır\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Видалити LuLu\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"لولو ان انسٹال کریں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"卸载LuLu\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"解除安裝 LuLu\"\n          }\n        }\n      }\n    },\n    \"Lse-DT-C0z.title\" : {\n      \"comment\" : \"Class = \\\"NSMenuItem\\\"; title = \\\"Cleanup\\\"; ObjectID = \\\"Lse-DT-C0z\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aufräumen\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Cleanup\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Limpiar\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nettoyage\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pulisci\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"정리\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Posprzątaj\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Limpeza\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Temizle\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Очистити\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"صاف کریں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"清理\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"清理\"\n          }\n        }\n      }\n    },\n    \"mxA-q2-fvN.title\" : {\n      \"comment\" : \"Class = \\\"NSMenuItem\\\"; title = \\\"Profile: Default\\\"; ObjectID = \\\"mxA-q2-fvN\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profil: Standard\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Profile: Default\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Perfil: Predeterminado\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profil : Par défaut\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profilo: Predefinito\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"프로필: 기본값\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profil: Domyślny\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Perfil: Padrão\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profil: Saptanmış\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Профіль: За замовчуванням\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"پروفائل: ڈیفالٹ\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"配置文件：Default\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"設定檔：預設\"\n          }\n        }\n      }\n    },\n    \"pF8-Hh-0tW.title\" : {\n      \"comment\" : \"Class = \\\"NSMenuItem\\\"; title = \\\"Manage...\\\"; ObjectID = \\\"pF8-Hh-0tW\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Verwalten…\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Manage...\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gestionar...\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gérer…\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gestisci…\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"관리...\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zarządzaj…\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gerenciar...\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Yönet…\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Керувати…\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"منظم کریں...\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"管理...\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"管理...\"\n          }\n        }\n      }\n    },\n    \"q1D-fP-yr1.title\" : {\n      \"comment\" : \"Class = \\\"NSMenuItem\\\"; title = \\\"About LuLu\\\"; ObjectID = \\\"q1D-fP-yr1\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Über LuLu\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"About LuLu\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Acerca de LuLu\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"À propos de LuLu\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Informazioni su LuLu\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu에 관하여\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"O LuLu\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sobre LuLu\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu Hakkında\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Про LuLu\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"لولو کے بارے میں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"关于LuLu\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"關於 LuLu\"\n          }\n        }\n      }\n    },\n    \"QrZ-U2-1Ib.title\" : {\n      \"comment\" : \"Class = \\\"NSMenuItem\\\"; title = \\\"Quit LuLu\\\"; ObjectID = \\\"QrZ-U2-1Ib\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu beenden\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Quit LuLu\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cerrar LuLu\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Quitter LuLu\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Chiudi LuLu\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu 종료\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wyjdź z LuLu\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Fechar LuLu\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu'dan Çık\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Закрити LuLu\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"لولو کو ختم کریں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"关闭LuLu\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"關閉 LuLu\"\n          }\n        }\n      }\n    },\n    \"uhX-d8-iZM.title\" : {\n      \"comment\" : \"Class = \\\"NSMenu\\\"; title = \\\"Main Menu\\\"; ObjectID = \\\"uhX-d8-iZM\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hauptmenü\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Main Menu\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Menú Principal\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Menu Principal\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Menu Principale\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"메인 매뉴\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Menu główne\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Menu Principal\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ana Menü\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Головне меню\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"مینیو\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"主菜单\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"主選單\"\n          }\n        }\n      }\n    },\n    \"UuL-hi-gEf.title\" : {\n      \"comment\" : \"Class = \\\"NSMenuItem\\\"; title = \\\"Rules\\\"; ObjectID = \\\"UuL-hi-gEf\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Regeln\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Rules\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Reglas\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Règles\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Regole\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"규칙\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Reguły\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Regras\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kurallar\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Правила\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"قوانین\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"规则\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"規則\"\n          }\n        }\n      }\n    },\n    \"vb5-99-ejR.title\" : {\n      \"comment\" : \"Class = \\\"NSMenu\\\"; title = \\\"Rules\\\"; ObjectID = \\\"vb5-99-ejR\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Regeln\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Rules\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Reglas\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Règles\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Regole\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"규칙\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Reguły\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Regras\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kurallar\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Правила\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"قوانین\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"规则\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"規則\"\n          }\n        }\n      }\n    },\n    \"VuY-Sy-392.title\" : {\n      \"comment\" : \"Class = \\\"NSMenuItem\\\"; title = \\\"Network Monitor...\\\"; ObjectID = \\\"VuY-Sy-392\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Netzwerkmonitor…\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Network Monitor...\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Monitor de Red...\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Moniteur réseau…\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Monitor di Rete…\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"네트워크 모니터...\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Monitor sieci...\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Monitor de Rede\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ağ Monitörü…\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Монітор мережі..\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"نیٹ ورک مانیٹر...\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"网络监控…\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"網路監控器...\"\n          }\n        }\n      }\n    },\n    \"w99-Wo-epe.title\" : {\n      \"comment\" : \"Class = \\\"NSMenuItem\\\"; title = \\\"LULU: enabled\\\"; ObjectID = \\\"w99-Wo-epe\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LULU: aktiviert\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"LULU: enabled\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LULU: habilitado\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LULU : activé\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LULU: abilitato\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LULU: 활성화됨\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LULU: włączona\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LULU: habilitado\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu: Etkin\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu: увімкнено\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"لولو: فعال\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu: 可用\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LULU：啟用\"\n          }\n        }\n      }\n    }\n  },\n  \"version\" : \"1.0\"\n}"
  },
  {
    "path": "LuLu/App/mul.lproj/Preferences.xcstrings",
    "content": "{\n  \"sourceLanguage\" : \"en\",\n  \"strings\" : {\n    \"2qr-2x-A3U.title\" : {\n      \"comment\" : \"Class = \\\"NSButtonCell\\\"; title = \\\"Check Now\\\"; ObjectID = \\\"2qr-2x-A3U\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Jetzt prüfen\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Check Now\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Verificar Ahora\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rechercher\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Verifica ora\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"지금 확인\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sprawdź teraz\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Verificar Agora\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Şimdi Denetle\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Перевірити\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ابھی چیک کریں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"立即检查\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"現在檢查\"\n          }\n        }\n      }\n    },\n    \"4EN-j2-enV.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"Block Mode\\\"; ObjectID = \\\"4EN-j2-enV\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Blockierungsmodus\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Block Mode\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modo Bloqueo\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mode blocage\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modalità Blocco\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"차단 모드\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tryb blokady\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bloquear Modo\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Engelleme kipi\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Режим блокування\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"بلاک موڈ\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"阻止模式\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"阻擋模式\"\n          }\n        }\n      }\n    },\n    \"5Fx-eu-v3J.title\" : {\n      \"comment\" : \"Class = \\\"NSButtonCell\\\"; title = \\\"Cancel\\\"; ObjectID = \\\"5Fx-eu-v3J\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Abbrechen\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Cancel\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cancelar\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Annuler\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Annulla\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"취소\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Anuluj\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cancelar\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"İptal\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Скасувати\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"منسوخ کریں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"取消\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"取消\"\n          }\n        }\n      }\n    },\n    \"5li-Ut-Gsb.label\" : {\n      \"comment\" : \"Class = \\\"NSToolbarItem\\\"; label = \\\"Profiles\\\"; ObjectID = \\\"5li-Ut-Gsb\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profile\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Profiles\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Perfiles\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profils\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profili\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"프로필\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profile\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Perfis\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profiller\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Профілі\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"پروفائلز\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"配置文件\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"設定檔\"\n          }\n        }\n      }\n    },\n    \"5li-Ut-Gsb.paletteLabel\" : {\n      \"comment\" : \"Class = \\\"NSToolbarItem\\\"; paletteLabel = \\\"Profiles\\\"; ObjectID = \\\"5li-Ut-Gsb\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profile\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Profiles\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Perfiles\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profils\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profili\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"프로필\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profile\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Perfis\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profiller\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Профілі\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"پروفائلز\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"配置文件\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"設定檔\"\n          }\n        }\n      }\n    },\n    \"5Wo-JL-Khb.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"Rules for new connections should be created?\\\"; ObjectID = \\\"5Wo-JL-Khb\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sollen Regeln für neue Verbindungen erstellt werden?\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Rules for new connections should be created?\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"¿Se deben crear reglas para nuevas conexiones?\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Faut-il créer des règles pour les nouvelles connexions ?\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Creare regole per le nuove connessioni?\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"새로운 연결에 관한 규칙을 생성할까요?\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Czy należy stworzyć reguły dla nowych połączeń?\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Criar regras para novas conexões?\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Yeni bağlantılar için kurallar oluşturulmalı mı?\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Створювати правила для нових з'єднань?\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"نئے کنکشنز کے لیے قواعد بنائے جائیں؟\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"是否应创建新连接规则？\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"是否應建立新連線的規則？\"\n          }\n        }\n      }\n    },\n    \"6gH-HW-CFe.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"Outgoing connections from currently installed 3rd-party programs will be allowed.\\\"; ObjectID = \\\"6gH-HW-CFe\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Bereits installierte Drittanbieterprogramme werden erlaubt.\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Outgoing connections from currently installed 3rd-party programs will be allowed.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Se permitirán los programas de terceros previamente instalados.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Programmes précédemment installées, les programmes de tierce-partie seront autorisés.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"I programmi di terze parti già installati saranno consentiti.\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"이전에 설치한 타사 프로그램을 허용합니다.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Wcześniej zainstalowane programy innych firm będą dozwolone.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Programas terceirizados previamente instalados serão permitidos.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Daha önceden kurulmuş, 3. parti uygulamalara izin verilecektir.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Раніше встановлені сторонні програми будуть дозволені.\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"پہلے سے انسٹال شدہ، تیسرے فریق کے پروگراموں کو اجازت دی جائے گی۔\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"先前安装的第三方程序将被允许。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"已安裝的第三方程式將被允許\"\n          }\n        }\n      }\n    },\n    \"6vU-GO-opk.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"Note: When a new connection is made, sometimes only the IP address may be available. In such cases, domains on the allow or block list cannot be matched, which may impact whether a request is blocked or allowed.\\\"; ObjectID = \\\"6vU-GO-opk\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hinweis: Wenn eine neue Verbindung hergestellt wird, ist manchmal nur die IP-Adresse verfügbar. In solchen Fällen können die Domains in der Erlauben- oder Blockieren-Liste nicht abgeglichen werden, was sich darauf auswirken kann, ob eine Anfrage blockiert oder erlaubt wird.\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Note: When a new connection is made, sometimes only the IP address may be available. In such cases, domains on the allow or block list cannot be matched, which may impact whether a request is blocked or allowed.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nota: cuando se hace una nueva conexión, a veces solo la dirección IP estará disponible. En esos casos, los dominios en la lista de permitidos o bloqueados no coincidirán, lo cual impactará si un pedido es bloqueado o permitido. \"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Note : lorsqu'une nouvelle connexion est établie, il arrive que seule l'adresse IP soit disponible. Dans ce cas, les domaines figurant sur la liste d'autorisation ou de blocage ne peuvent être mis en correspondance, ce qui peut avoir une incidence sur le fait que la demande soit bloquée ou autorisée.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nota: Quando viene stabilita una nuova connessione, a volte è disponibile solo l’indirizzo IP. In questi casi, i domini nell’elenco di blocco o autorizzazione potrebbero non essere riconosciuti, il che può influire sul fatto che una richiesta venga bloccata o consentita.\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"참고: 새로운 연결이 만들어질 때, 때때로 IP 주소만 이용 가능할 수 있습니다. 이러한 경우, 허용 리스트 또는 차단 리스트의 도메인과 일치시킬 수 없으며, 이로 인해 요청이 차단되거나 허용될지에 영향이 있을 수 있습니다.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Uwaga: Kiedy nawiązywane jest nowe połączenie, czasami dostępny może być tylko adres IP. W takich przypadkach domeny na liście dozwolonych lub blokowanych nie mogą zostać dopasowane, co może mieć wpływ na to, czy żądanie zostanie zablokowane, czy dozwolone.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nota: quando uma nova conexão é feita, às vezes somente o endereço de IP estará disponível. Nestes casos, os domínios nas listas de permissão ou bloqueio não conseguirão ser encontrados, o que pode impactar se a solicitação será bloqueada ou permitida.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Not: Yeni bir bağlantı yapıldığında, bazen yalnızca IP adresi kullanılabilir olabilir. Bu tür durumlarda, izin verilenler veya engellenenler listesindeki etki alanları eşleştirilemez; bu, bir bağlantının engellenip engellenmeyeceğine etki edebilir.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Примітка: Коли встановлюється нове з'єднання, іноді доступна лише IP-адреса. У таких випадках не можна зіставити домени зі списком дозволених або заблокованих, що може вплинути на те, чи буде запит заблоковано або дозволено.\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"نوٹ: جب ایک نیا کنکشن بنایا جاتا ہے، تو بعض اوقات صرف IP ایڈریس دستیاب ہوتا ہے۔ ایسے معاملات میں، اجازت یا بلاک لسٹ پر موجود ڈومینز کا مقابلہ نہیں کیا جا سکتا، جس سے یہ متاثر ہو سکتا ہے کہ درخواست بلاک کی جائے گی یا اجازت دی جائے گی۔\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"注意：建立新连接时，有时可能只有 IP 地址可用。在这种情况下，允许或阻止列表中的域名将无法匹配，这可能会影响请求是被阻止还是被允许。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"注意：當建立新的連線時，有時只有 IP 位址可用。在此情況下，允許或阻擋名單上的網域無法配對，這可能會影響連線請求是否被阻擋或允許。\"\n          }\n        }\n      }\n    },\n    \"7iJ-xR-xDI.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"Local or remote file, containing endpoints to always allow.\\\"; ObjectID = \\\"7iJ-xR-xDI\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lokale oder externe Datei, die Endpunkte enthält, die immer erlaubt werden sollen.\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Local or remote file, containing endpoints to always allow.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Archivo local o remoto, que contiene endpoints para bloquear siempre. \"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Fichier local ou distant contenant les points d’accès à toujours autoriser.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"File locale o remoto contenente endpoint da consentire sempre.\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"항상 허용할 엔드포인트를 포함한 로컬 또는 원격 파일\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Plik lokalny lub zdalny, zawierający punkty końcowe, na które zawsze należy zezwolić.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Arquivo local ou remoto, contendo endpoints para sempre permitir.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Yerel veya uzak dosya, her zaman izin verilecek içeren bitiş noktaları.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Файл, що містить веб- або IP-адреси, які завжди дозволено.\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"مقامی یا ریموٹ فائل، جس میں ہمیشہ اجازت دینے والے اینڈ پوائنٹس شامل ہیں۔\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"本地或远程文件，包含始终允许的端点。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"本地或遠端檔案，包含總是允許的端點。\"\n          }\n        }\n      }\n    },\n    \"7vn-ff-PJk.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"Note: A profile defines a set of rules and settings. Once activated, its settings apply LuLu-wide (and can be modified via LuLu's Settings panes). Any new rules will be added only to that profile's ruleset.\\\"; ObjectID = \\\"7vn-ff-PJk\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hinweis: Ein Profil definiert eine Reihe von Regeln und Einstellungen. Sobald es aktiviert ist, gelten diese Einstellungen für ganz LuLu (und können in den LuLu-Einstellungen geändert werden). Neue Regeln werden nur zu diesem Profil hinzugefügt.\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Note: A profile defines a set of rules and settings. Once activated, its settings apply LuLu-wide (and can be modified via LuLu's Settings panes). Any new rules will be added only to that profile's ruleset.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nota: Un perfil define un conjunto de reglas y configuraciones. Una vez activado, sus configuraciones se aplican en todo LuLu (y se pueden modificar en los paneles de Configuración de LuLu). Cualquier regla nueva se añadirá solo al conjunto de reglas de ese perfil.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Remarque : un profil définit un ensemble de règles et de paramètres. Une fois activé, ses paramètres s’appliquent à l’ensemble de LuLu (et peuvent être modifiés dans les panneaux de paramètres de LuLu). Toute nouvelle règle sera ajoutée uniquement à l’ensemble de règles de ce profil.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nota: Un profilo definisce un insieme di regole e impostazioni. Una volta attivato, le sue impostazioni si applicano in tutto LuLu (e possono essere modificate nei pannelli Impostazioni di LuLu). Eventuali nuove regole verranno aggiunte solo al set di regole di quel profilo.\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"참고: 프로필은 일련의 규칙과 설정을 정의합니다. 활성화되면 해당 설정이 LuLu 전체에 적용되며 (LuLu의 설정 창에서 수정할 수 있습니다). 새 규칙은 해당 프로필의 규칙 집합에만 추가됩니다.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Uwaga: Profil definiuje zestaw reguł i ustawień. Po aktywowaniu ustawienia te mają zastosowanie w całym LuLu (i mogą być zmieniane w panelach ustawień LuLu). Nowe reguły będą dodawane tylko do zestawu reguł tego profilu.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nota: Um perfil define um conjunto de regras e configurações. Uma vez ativado, suas configurações são aplicadas em todo o LuLu (e podem ser modificadas nos painéis de Configurações do LuLu). Novas regras serão adicionadas somente ao conjunto de regras desse perfil.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Not: Bir profil, bir dizi kural ve ayar tanımlar. Etkinleştirildiğinde bu ayarlar LuLu genelinde geçerli olur (ve LuLu’nun Ayarlar pencerelerinden değiştirilebilir). Yeni kurallar yalnızca o profilin kural kümesine eklenir.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Примітка: профіль визначає набір правил і налаштувань. Після активації його параметри застосовуються в LuLu (і можуть бути змінені через панелі налаштувань LuLu). Будь-які нові правила буде додано лише до набору правил цього профілю.\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"نوٹ: ایک پروفائل قواعد اور ترتیبات کا مجموعہ متعین کرتا ہے۔ فعال ہونے کے بعد، اس کی ترتیبات پوری LuLu پر لاگو ہوں گی (اور انہیں LuLu کی ترتیبات میں ترمیم کیا جا سکتا ہے)۔ کوئی بھی نیا قاعدہ صرف اسی پروفائل کے قواعد میں شامل کیا جائے گا۔\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"注意：配置文件定义了一组规则和设置。激活后，其设置将在整个 LuLu 中生效（并可通过 LuLu 的“设置”面板进行修改）。任何新规则都只会添加到该配置文件的规则集中。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"注意：設定檔定義了一組規則與設定。啟用後，其設定將套用於整個 LuLu（並可透過 LuLu 的設定面板修改）。任何新的規則只會新增到該設定檔的規則集中。\"\n          }\n        }\n      }\n    },\n    \"9ts-yW-4uE.headerCell.title\" : {\n      \"comment\" : \"Class = \\\"NSTableColumn\\\"; headerCell.title = \\\"Selected Profile\\\"; ObjectID = \\\"9ts-yW-4uE\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ausgewähltes Profil\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Selected Profile\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Perfil seleccionado\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profil sélectionné\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profilo Selezionato\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"선택된 프로필\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wybrany profil\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Perfil selecionado\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Seçili Profil\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Вибраний профіль\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"منتخب کردہ پروفائل\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"已选择的配置文件\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"已選取的設定檔\"\n          }\n        }\n      }\n    },\n    \"Bdp-Z8-BhB.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"Local or remote file, containing endpoints to always block.\\\"; ObjectID = \\\"Bdp-Z8-BhB\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lokale oder externe Datei, die Endpunkte enthält, die immer blockiert werden sollen.\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Local or remote file, containing endpoints to always block.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Archivo local o remoto, que contiene endpoints para bloquear siempre. \"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Fichier local ou distant contenant les points d’accès à toujours bloquer.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"File locale o remoto contenente endpoint da bloccare sempre.\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"항상 차단할 엔드포인트를 포함한 로컬 또는 원격 파일\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Plik lokalny lub zdalny, zawierający punkty końcowe, które należy zawsze blokować.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Arquivo local ou remoto, contendo endpoints para sempre bloquear.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Yerel veya uzak dosya, her zaman engellenecek içeren bitiş noktaları.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Файл, що містить веб- або IP-адреси, які завжди блокуються.\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"مقامی یا ریموٹ فائل، جس میں ہمیشہ بلاک کرنے والے اینڈ پوائنٹس شامل ہیں۔\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"本地或远程文件，包含始终要阻止的端点。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"本地或遠端檔案，包含總是阻擋的端點。\"\n          }\n        }\n      }\n    },\n    \"bYB-s1-S3f.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"Run without showing an icon in the status menu bar.\\\"; ObjectID = \\\"bYB-s1-S3f\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ausführen, ohne ein Statussymbol in der Menüleiste anzuzeigen.\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Run without showing an icon in the status menu bar.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ejecutar sin mostrar un ícono en la barra de menú de estado.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Exécuter sans afficher d'icône dans la barre de menu.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"File locale o remoto contenente endpoint da bloccare sempre.\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"상태 메뉴 막대에 아이콘을 표시하지 않습니다.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Uruchom bez wyświetlania ikony na pasku menu stanu.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rodar sem mostrar ícone de staus na barra do menu.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Menü çubuğunda bir simge göstermeden çalıştırın.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Запускати без зображення іконки в панелі меню.\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"اسٹیٹس مینو بار میں آئیکن کو ظاہر کیے بغیر چلائیں۔\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"运行时不在状态菜单栏中显示图标。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"執行時不於選單列中顯示圖示。\"\n          }\n        }\n      }\n    },\n    \"caA-Ec-ysj.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"Outgoing connections to localhost will be allowed.\\\"; ObjectID = \\\"caA-Ec-ysj\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Outgoing connections to localhost will be allowed.\"\n          }\n        }\n      }\n    },\n    \"Cfj-2E-dIA.title\" : {\n      \"comment\" : \"Class = \\\"NSButtonCell\\\"; title = \\\"View Rules\\\"; ObjectID = \\\"Cfj-2E-dIA\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Regeln anzeigen\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"View Rules\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ver Reglas\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Voir les règles\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Visualizza Regole\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"규칙 보기\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zobacz reguły\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ver Regras\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kuralları Görüntüle\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Переглянути правила\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"قواعد دیکھیں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"查看规则\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"查看規則\"\n          }\n        }\n      }\n    },\n    \"CqC-4v-5d3.title\" : {\n      \"comment\" : \"Class = \\\"NSMenuItem\\\"; title = \\\"Allowed\\\"; ObjectID = \\\"CqC-4v-5d3\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Erlauben\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Allowed\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Permitido\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Autorisé\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Consentito\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"허용\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dozwolone\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Permitido\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"İzin ver\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Дозволено\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"اجازت دی گئی\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"已允许\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"允許\"\n          }\n        }\n      }\n    },\n    \"d79-kw-Ala.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"First create a name for your profile. \\\\n\\\\nThen click \\\\\\\"Next\\\\\\\" to configure the settings for your new profile.\\\"; ObjectID = \\\"d79-kw-Ala\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Erstellen Sie zuerst einen Namen für Ihr Profil.\\n\\nKlicken Sie dann auf „Weiter“, um die Einstellungen für Ihr neues Profil zu konfigurieren.\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"First create a name for your profile. \\n\\nThen click \\\"Next\\\" to configure the settings for your new profile.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Primero cree un nombre para su perfil.\\n\\nLuego haga clic en “Siguiente” para configurar los ajustes de su nuevo perfil.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Créez d’abord un nom pour votre profil.\\n\\nCliquez ensuite sur « Suivant » pour configurer les paramètres de votre nouveau profil.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Crea prima un nome per il tuo profilo. \\n\\nPoi fai clic su “Avanti” per configurare le impostazioni del tuo nuovo profilo.\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"먼저 프로필 이름을 만드세요.\\n\\n그런 다음 \\\"다음\\\"을 클릭하여 새 프로필의 설정을 구성하세요.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Najpierw utwórz nazwę dla swojego profilu.\\n\\nNastępnie kliknij „Dalej”, aby skonfigurować ustawienia nowego profilu.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Primeiro crie um nome para o seu perfil.\\n\\nEm seguida, clique em “Avançar” para configurar as configurações do seu novo perfil.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Önce profiliniz için bir ad oluşturun.\\n\\nArdından yeni profilinizin ayarlarını yapılandırmak için “İleri”ye tıklayın.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Спочатку створіть назву для свого профілю.\\n\\nПотім натисніть «Далі», щоб налаштувати параметри для нового профілю.\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"سب سے پہلے اپنے پروفائل کے لیے ایک نام بنائیں۔\\n\\nپھر \\\"اگلا\\\" پر کلک کریں تاکہ اپنے نئے پروفائل کی ترتیبات تشکیل دیں۔\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"请先为您的配置文件创建一个名称。\\n然后点击“下一步”来配置新配置文件的设置。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"請先為您的設定檔建立名稱。 \\n\\n然後點擊「下一步」以設定新設定檔的選項。\"\n          }\n        }\n      }\n    },\n    \"E0T-Ug-P8f.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"Silently run without alerts, applying existing rules.\\\"; ObjectID = \\\"E0T-Ug-P8f\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Stille Ausführung ohne Mitteilungen unter Anwendung bestehender Regeln.\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Silently run without alerts, applying existing rules.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ejecutar silenciosamente sin alertas, aplicando reglas existentes.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Exécution silencieuse sans alerte, en appliquant les règles existantes.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Esegui in silenzio senza avvisi, applicando le regole esistenti.\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"기존 규칙을 적용하고, 경고 없이 조용히 실행합니다.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Działa w trybie cichym, bez alertów, stosując istniejące reguły.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rodar silenciado sem alertas, aplicando regras existentes.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"İkaz olmadan sessizce çalıştırın ve var olan kuralları uygulayın.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Запускати у фоновому режимі без сповіщень і застосовувати наявні правила.\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"الرٹس کے بغیر خاموشی سے چلائیں اور موجودہ قواعد کو لاگو کریں۔\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"静默运行，不发出警报，应用现有规则。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"執行時不顯示警告，自動套用現有規則。\"\n          }\n        }\n      }\n    },\n    \"e5A-iH-fS4.title\" : {\n      \"comment\" : \"Class = \\\"NSMenuItem\\\"; title = \\\"Yes\\\"; ObjectID = \\\"e5A-iH-fS4\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ja\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Yes\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sí\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Oui\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sì\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"예\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tak\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sim\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Evet\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Так\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ہاں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"是\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"是\"\n          }\n        }\n      }\n    },\n    \"e6s-dd-HG6.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"Outgoing connections from programs running in the (iOS) simulator will be allowed.\\\"; ObjectID = \\\"e6s-dd-HG6\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Programme, welche in einem Simulator laufen, werden erlaubt.\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Outgoing connections from programs running in the (iOS) simulator will be allowed.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Se permitirán las aplicaciones que se ejecuten dentro del simulador.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Les applications fonctionnant dans le simulateur sont autorisées.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Le applicazioni in esecuzione nel simulatore saranno consentite.\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"시뮬레이터 내에서 실행되는 애플리케이션을 허용합니다.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Aplikacje działające w symulatorze będą dozwolone.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Aplicações rodando no simulador serão permitidas.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Simülatörde çalışan uygulamalara izin verilecektir.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Програми, що працюють у середовищі Симулятора, будуть дозволені.\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"سیمولیٹر کے اندر چلنے والی ایپلیکیشنز کو اجازت دی جائے گی۔\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"将允许在模拟器内运行的应用程序。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"執行於模擬器內的應用程式將被允許\"\n          }\n        }\n      }\n    },\n    \"Emd-wS-UQh.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"Block List:\\\"; ObjectID = \\\"Emd-wS-UQh\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Blockieren-Liste:\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Block List:\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lista de Bloqueados:\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Liste de blocage :\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Elenco Blocco:\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"차단 리스트:\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lista zablokowanych:\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lista de Bloqueio:\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Engel listesi:\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Список заблокованих:\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"بلاک لسٹ:\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"阻止列表：\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"阻擋名單\"\n          }\n        }\n      }\n    },\n    \"F0z-JX-Cv5.title\" : {\n      \"comment\" : \"Class = \\\"NSWindow\\\"; title = \\\"Settings\\\"; ObjectID = \\\"F0z-JX-Cv5\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Einstellungen\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Settings\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configuración\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Paramètres\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Impostazioni\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"설정\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ustawienia\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configurações\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ayarlar\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Параметри\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ترتیبات\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"设置\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"設定\"\n          }\n        }\n      }\n    },\n    \"F6g-hE-DiK.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"Allow Localhost Traffic\\\"; ObjectID = \\\"F6g-hE-DiK\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Allow Localhost Traffic\"\n          }\n        }\n      }\n    },\n    \"FE3-Li-d3K.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"Allow List:\\\"; ObjectID = \\\"FE3-Li-d3K\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Erlauben-Liste:\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Allow List:\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lista de Permitidos:\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Liste d’autorisation :\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Elenco Consenti:\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"허용 리스트:\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lista dozwolonych:\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lista de Permissões:\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"İzin listesi:\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Список дозволених:\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"اجازت دی گئی لسٹ:\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Allow List:\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"允許名單\"\n          }\n        }\n      }\n    },\n    \"Fut-ad-zCW.title\" : {\n      \"comment\" : \"Class = \\\"NSButtonCell\\\"; title = \\\"Browse\\\"; ObjectID = \\\"Fut-ad-zCW\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Durchsuchen\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Browse\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Navegar\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Parcourir\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sfoglia\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"찾아보기\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Przeglądaj\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Buscar\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Göz At\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Переглянути\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"براؤز کریں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"浏览\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"瀏覽\"\n          }\n        }\n      }\n    },\n    \"GRx-gM-j7j.headerCell.title\" : {\n      \"comment\" : \"Class = \\\"NSTableColumn\\\"; headerCell.title = \\\"Profile Name\\\"; ObjectID = \\\"GRx-gM-j7j\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profilname\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Profile Name\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nombre del perfil\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nom du profil\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nome Profilo\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"프로필 이름\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nazwa profilu\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nome do perfil\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profil Adı\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Назва профілю\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"روفائل کا نام\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"配置文件名称\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"設定檔名稱\"\n          }\n        }\n      }\n    },\n    \"GsR-9d-5N8.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"New connections should be be:\\\"; ObjectID = \\\"GsR-9d-5N8\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Neue Verbindungen:\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"New connections should be be:\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Las nuevas conexiones deben ser:\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Les nouvelles connections doivent être :\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Le nuove connessioni dovrebbero essere:\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"새로운 연결을 항상:\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nowe połączenia powinny być:\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Novas conexões devem ser:\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Yeni bağlantılara:\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Нові з'єднання мають бути:\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"نئی کنکشنز کو ہونا چاہیے:\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"新的连接应该是：\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"新的連線應被：\"\n          }\n        }\n      }\n    },\n    \"I4i-8n-Kep.placeholderString\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; placeholderString = \\\"Profile Name\\\"; ObjectID = \\\"I4i-8n-Kep\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profilname\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Profile Name\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nombre del perfil\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nom du profil\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nome Profilo\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"프로필 이름\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nazwa profilu\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nome do perfil\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profil Adı\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Назва профілю\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"روفائل کا نام\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"配置文件名称\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"設定檔名稱\"\n          }\n        }\n      }\n    },\n    \"ICK-Xr-yt1.title\" : {\n      \"comment\" : \"Class = \\\"NSButtonCell\\\"; title = \\\"Add Profile\\\"; ObjectID = \\\"ICK-Xr-yt1\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profil hinzufügen\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Add Profile\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Agregar perfil\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ajouter un profil\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aggiungi Profilo\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"프로필 추가\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dodaj profil\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Adicionar perfil\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profil Ekle\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Додати профіль\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"روفائل کا نام\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"添加配置文件\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"新增設定檔\"\n          }\n        }\n      }\n    },\n    \"iOJ-Bc-hxG.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"No Icon Mode\\\"; ObjectID = \\\"iOJ-Bc-hxG\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kein-Statussymbol-Modus\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"No Icon Mode\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modo Sin Ícono\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mode sans icône\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modalità senza icona\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"아이콘 비활성화 모드\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tryb bez ikony\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modo Sem Ícone\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Simgesiz kip\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Режим без іконки\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"آئیکن کے بغیر موڈ\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"无图标模式\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"無圖示模式\"\n          }\n        }\n      }\n    },\n    \"iYm-DO-gHs.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"All outgoing UDP traffic on port 53 will be allowed.\\\"; ObjectID = \\\"iYm-DO-gHs\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Alle (UDP-)Verbindungen auf Port 53 werden erlaubt.\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"All outgoing UDP traffic on port 53 will be allowed.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Todo el tráfico (UDP) en el puerto 53 será permitido. \"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Tout le trafic (UDP) sur le port 53 sera autorisé.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Tutto il traffico (UDP) sulla porta 53 sarà consentito.\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"53번 포트를 통하는 모든 (UDP) 트래픽을 허용합니다.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Cały ruch (UDP) na porcie 53 będzie dozwolony.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Todo tráfego (UDP) na porta 53 será permitido.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"53. kapıdaki tüm (UDP) trafiğe izin verilecektir.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Увесь (UDP) трафік на порту 53 буде дозволено.\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"پورٹ 53 پر تمام (UDP) ٹریفک کو اجازت دی جائے گی۔\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"允许端口 53 上的所有 (UDP) 流量。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"所有 53 連接埠的 （UDP）流量將被允許。\"\n          }\n        }\n      }\n    },\n    \"JV5-cY-ff4.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"Do not automatically check for new versions.\\\"; ObjectID = \\\"JV5-cY-ff4\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nicht automatisch nach Updates suchen.\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Do not automatically check for new versions.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"No verificar automáticamente nuevas versiones. \"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ne pas rechercher automatiquement la présence de nouvelles versions.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Non controllare automaticamente la disponibilità di nuove versioni.\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"자동으로 새로운 버전을 확인하지 않습니다.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nie sprawdzaj automatycznie dostępności nowych wersji.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Não verifique novas atualizações  automaticamente.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Yeni sürümleri kendiliğinden denetlemeyin.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Не перевіряти наявність нових версій автоматично.\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"نئی ورژنز کے لیے خودکار طور پر چیک نہ کریں۔\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"不自动检查新版本。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"不自動檢查新版本。\"\n          }\n        }\n      }\n    },\n    \"JVI-Or-h0u.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"Passive Mode\\\"; ObjectID = \\\"JVI-Or-h0u\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Passiver Modus\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Passive Mode\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modo Pasivo\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mode passif\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modalità Passiva\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"패시브 모드\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tryb pasywny\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modo Passivo\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pasif kip\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Пасивний режим\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"پسیو موڈ\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"被动模式\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"被動模式\"\n          }\n        }\n      }\n    },\n    \"jvT-uI-uNq.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"Allow Already Installed Programs\\\"; ObjectID = \\\"jvT-uI-uNq\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Bereits installierte Programme erlauben.\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Allow Already Installed Programs\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Permitir Programas Instalados\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Autoriser les programmes installés\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Consenti Programmi Installati\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"설치된 프로그램 허용\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Zezwalaj na zainstalowane programy\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Permitir Programas Instalados\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Kurulu programlara izin ver\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Дозволити установлені програми\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"انسٹال شدہ پروگراموں کو اجازت دیں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"允许已安装的程序\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"允許已安裝程式\"\n          }\n        }\n      }\n    },\n    \"JwN-0v-5Uh.title\" : {\n      \"comment\" : \"Class = \\\"NSMenuItem\\\"; title = \\\"No\\\"; ObjectID = \\\"JwN-0v-5Uh\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nein\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"No\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"No\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Non\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"No\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"아니요\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nie\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Não\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hayır\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ні\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"نہیں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"否\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"否\"\n          }\n        }\n      }\n    },\n    \"k0w-Oi-kwd.label\" : {\n      \"comment\" : \"Class = \\\"NSToolbarItem\\\"; label = \\\"Mode\\\"; ObjectID = \\\"k0w-Oi-kwd\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modus\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Mode\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modo\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mode\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modalità\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"모드\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tryb\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modo\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kip\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Режим\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"موڈ\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"模式\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"模式\"\n          }\n        }\n      }\n    },\n    \"k0w-Oi-kwd.paletteLabel\" : {\n      \"comment\" : \"Class = \\\"NSToolbarItem\\\"; paletteLabel = \\\"Mode\\\"; ObjectID = \\\"k0w-Oi-kwd\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modus\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Mode\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modo\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mode\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modalità\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"모드\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tryb\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modo\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kip\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Режим\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"موڈ\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"模式\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"模式\"\n          }\n        }\n      }\n    },\n    \"kZA-kY-nGm.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"Profile Name:\\\"; ObjectID = \\\"kZA-kY-nGm\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profilname\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Profile Name:\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nombre del perfil:\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nom du profil :\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nome Profilo:\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"프로필 이름:\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nazwa profilu:\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nome do perfil:\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profil Adı:\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Назва профілю:\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"روفائل کا نام:\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"配置文件名称：\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"設定檔名稱:\"\n          }\n        }\n      }\n    },\n    \"M8X-n4-v2d.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"Outgoing connections from Apple-signed programs will be allowed.\\\"; ObjectID = \\\"M8X-n4-v2d\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Von Apple signierte Programme werden erlaubt.\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Outgoing connections from Apple-signed programs will be allowed.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Se permitirán los binarios firmados por Apple.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Les binaires signés par Apple seront autorisés.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"I binari firmati da Apple saranno consentiti.\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Apple에 의해 서명된 실행 파일을 허용합니다.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Dozwolone będą pliki binarne podpisane przez Apple.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Binários assinados pela Apple serão permitidos.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Apple tarafından imzalanan ikililere izin verilecektir.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Бінарні файли, підписані Apple, будуть дозволені.\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"ایپل کے دستخط شدہ بائنریز کو اجازت دی جائے گی۔\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"将允许使用 Apple 签名的二进制文件。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"由 Apple 簽署的程式將被允許\"\n          }\n        }\n      }\n    },\n    \"mCn-AV-g9h.title\" : {\n      \"comment\" : \"Class = \\\"NSMenuItem\\\"; title = \\\"Blocked\\\"; ObjectID = \\\"mCn-AV-g9h\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Blockieren\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Blocked\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bloqueado\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bloqué\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bloccato\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"차단\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zablokowany\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bloqueado\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Engelle\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Заблоковано\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"بلاک\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"已阻止\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"阻擋\"\n          }\n        }\n      }\n    },\n    \"pGG-dq-qkU.label\" : {\n      \"comment\" : \"Class = \\\"NSToolbarItem\\\"; label = \\\"Update\\\"; ObjectID = \\\"pGG-dq-qkU\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Update\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Update\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Actualizar\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modifier\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aggiorna\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"업데이트\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aktualizacja\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Atualizar\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Güncelle\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Оновити\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"اپڈیٹ\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"更新\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"更新\"\n          }\n        }\n      }\n    },\n    \"pGG-dq-qkU.paletteLabel\" : {\n      \"comment\" : \"Class = \\\"NSToolbarItem\\\"; paletteLabel = \\\"Update\\\"; ObjectID = \\\"pGG-dq-qkU\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Update\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Update\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Actualizar\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modifier\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aggiorna\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"업데이트\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aktualizacja\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Atualizar\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Güncelle\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Оновити\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"اپڈیٹ\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"更新\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"更新\"\n          }\n        }\n      }\n    },\n    \"rrF-xj-cXp.label\" : {\n      \"comment\" : \"Class = \\\"NSToolbarItem\\\"; label = \\\"Lists\\\"; ObjectID = \\\"rrF-xj-cXp\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Listen\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Lists\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Listas\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Listes\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Elenchi\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"리스트\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Listy\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Listas\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Listeler\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Списки\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"فہرستیں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"列表\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"名單\"\n          }\n        }\n      }\n    },\n    \"rrF-xj-cXp.paletteLabel\" : {\n      \"comment\" : \"Class = \\\"NSToolbarItem\\\"; paletteLabel = \\\"Lists\\\"; ObjectID = \\\"rrF-xj-cXp\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Listen\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Lists\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Listas\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Listes\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Elenchi\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"리스트\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Listy\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Listas\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Listeler\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Списки\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"فہرستیں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"列表\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"名單\"\n          }\n        }\n      }\n    },\n    \"SG5-YM-BoV.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"All traffic routed thru LuLu will be blocked (unless the endpoint is explicitly on the 'Allow' list).\\\"; ObjectID = \\\"SG5-YM-BoV\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Alle über LuLu geleiteten Verbindungen werden blockiert (es sei denn, der Endpunkt ist ausdrücklich in der „Erlauben“-Liste aufgeführt).\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"All traffic routed thru LuLu will be blocked (unless the endpoint is explicitly on the 'Allow' list).\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Todo el tráfico ruteado a través de LuLu será bloqueado (a menos que el endpoint esté explícito en la lista de 'Permitidos').\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tout le trafic acheminé par LuLu sera bloqué (à moins que le point d’accès ne figure explicitement sur la liste 'Autoriser').\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tutto il traffico instradato tramite LuLu verrà bloccato (a meno che l’endpoint non sia esplicitamente presente nell’elenco “Consenti”).\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu를 통하는 모든 트래픽을 차단합니다. (엔드포인트가 '허용' 리스트에 명시적으로 있지 않은 경우)\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cały ruch kierowany przez LuLu zostanie zablokowany (chyba że punkt końcowy znajduje się wyraźnie na liście „Zezwól”).\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Todo tráfego roteado pelo LuLu será bloqueado (a menos que o endpoint esteja explicitamente na lista de ‘Permissões’).\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu üzerinden aktarılan tüm trafik engellenir (bitiş noktası açıkça “İzin Ver” listesinde değilse).\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Увесь трафік, що проходить через LuLu, буде заблоковано (якщо веб- або IP-адреса не в списку «Дозволених»).\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"لولو کے ذریعے روٹ کیا گیا تمام ٹریفک بلاک کر دیا جائے گا (جب تک کہ اینڈ پوائنٹ واضح طور پر 'اجازت' کی فہرست میں نہ ہو)۔\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"通过 LuLu 路由的所有流量都将被阻止（除非端点明确位于“允许”列表中）。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"所有經由 LuLu 路由的流量將被阻擋（除非該端點被列於允許名單中）。\"\n          }\n        }\n      }\n    },\n    \"Shu-Wz-4ax.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"Allow Apple Programs\\\"; ObjectID = \\\"Shu-Wz-4ax\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Apple-Programme erlauben\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Allow Apple Programs\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Permitir Programas de Apple\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Autoriser les programmes Apple\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Consenti Programmi Apple\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Apple 프로그램 허용\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zezwalaj na programy Apple\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Permitir Programas Apple\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Apple programlarına izin ver\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Дозволити програми Apple\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ایپل پروگراموں کو اجازت دیں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"允许 Apple 程序\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"允許 Apple 程式\"\n          }\n        }\n      }\n    },\n    \"Twx-TJ-y2Q.label\" : {\n      \"comment\" : \"Class = \\\"NSToolbarItem\\\"; label = \\\"Rules\\\"; ObjectID = \\\"Twx-TJ-y2Q\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Regeln\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Rules\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Reglas\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Règles\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Regole\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"규칙\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Reguły\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Regras\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kurallar\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Правила\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"قواعد\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"规则\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"規則\"\n          }\n        }\n      }\n    },\n    \"Twx-TJ-y2Q.paletteLabel\" : {\n      \"comment\" : \"Class = \\\"NSToolbarItem\\\"; paletteLabel = \\\"Rules\\\"; ObjectID = \\\"Twx-TJ-y2Q\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Regeln\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Rules\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Reglas\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Règles\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Regole\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"규칙\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Reguły\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Regras\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kurallar\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Правила\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"قواعد\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"规则\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"規則\"\n          }\n        }\n      }\n    },\n    \"Uqq-dW-xf2.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"Allow Simulator Programs\\\"; ObjectID = \\\"Uqq-dW-xf2\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Simulator-Anwendungen erlauben\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Allow Simulator Programs\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Permitir Aplicaciones del Simulador\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Autoriser les applications du simulateur\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Consenti Applicazioni del Simulatore\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"시뮬레이터 애플리케이션 허용\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Zezwalaj na aplikacje symulacyjne\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Permitir Aplicações do Simulador\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Simülatör uygulamalarına izin ver\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Дозволити програми Симулятора\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"سیمولیٹر ایپلیکیشنز کو اجازت دیں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"允许模拟器应用程序\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"允許模擬器內的應用程式\"\n          }\n        }\n      }\n    },\n    \"W6X-IU-31r.title\" : {\n      \"comment\" : \"Class = \\\"NSButtonCell\\\"; title = \\\"Browse\\\"; ObjectID = \\\"W6X-IU-31r\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Durchsuchen\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Browse\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Navegar\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Parcourir\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sfoglia\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"찾아보기\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Przeglądaj\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Buscar\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Göz At\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Переглянути\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"براؤز کریں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"浏览\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"瀏覽\"\n          }\n        }\n      }\n    },\n    \"wED-Z0-197.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"Allow DNS Traffic\\\"; ObjectID = \\\"wED-Z0-197\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"DNS-Verbindungen erlauben\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Allow DNS Traffic\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Permitir Tráfico DNS\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Autoriser le trafic DNS\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Consenti Traffico DNS\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"DNS 트래픽 허용\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zezwól na ruch DNS\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Permitir Tráfego DNS\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"DNS trafiğine izin ver\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Дозволити DNS трафік\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"DNS ٹریفک کو اجازت دیں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"允许 DNS 流量\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"允許 DNS 流量\"\n          }\n        }\n      }\n    },\n    \"wka-xk-z2g.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"No VirusTotal Mode\\\"; ObjectID = \\\"wka-xk-z2g\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kein-VirusTotal-Modus\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"No VirusTotal Mode\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modo Sin VirusTotal\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mode sans VirusTotal\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modalità senza VirusTotal\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"VirusTotal 비활성화 모드\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bez trybu VirusTotal\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modo sem vírusTotal\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"VirusTotal kipi yok\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Режим без VirusTotal\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"وائرس ٹوٹل موڈ نہیں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"无 VirusTotal 模式\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"無 VirusTotal 模式\"\n          }\n        }\n      }\n    },\n    \"wVp-l1-Eac.title\" : {\n      \"comment\" : \"Class = \\\"NSButtonCell\\\"; title = \\\"Next\\\"; ObjectID = \\\"wVp-l1-Eac\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profilname\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Next\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Siguiente\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Suivant\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Avanti\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"다음\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dalej\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Avançar\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"İleri\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Далі\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"اگلا\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"下一步\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"下一步\"\n          }\n        }\n      }\n    },\n    \"XTD-vf-hNE.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"Disable integration with VirusTotal.\\\"; ObjectID = \\\"XTD-vf-hNE\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"VirusTotal-Integration deaktivieren.\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Disable integration with VirusTotal.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Deshabilitar la integración con VirusTotal.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Désactiver l'intégration avec VirusTotal.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Disabilita integrazione con VirusTotal.\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"내장된 VirusTotal 연동 기능을 비활성화합니다.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wyłącz integrację z VirusTotal.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desabilite a integração com o VirusTotal.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"VirusTotal ile entegrasyonu devre dışı bırakın.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Вимкнути інтеграцію з VirusTotal.\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"وائرس ٹوٹل کے ساتھ انضمام کو غیر فعال کریں۔\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"禁用与 VirusTotal 的集成。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"停用與 VirusTotal 的整合功能。\"\n          }\n        }\n      }\n    },\n    \"z5b-fA-WCk.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"Disable Update Checks\\\"; ObjectID = \\\"z5b-fA-WCk\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Update-Prüfungen deaktivieren\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Disable Update Checks\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Deshabilitar Verificación de Actualizaciones\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Désactiver la recherche de mise à jour\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Disabilita Verifica Aggiornamenti\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"업데이트 확인 비활성화\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wyłącz sprawdzanie aktualizacji\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desabilitar Verificação de Atualizações\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Güncelleme denetimlerini devre dışı bırak\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Вимкнути перевірку оновлень\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"اپڈیٹ چیکس کو غیر فعال کریں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"禁用更新检查\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"停用更新檢查\"\n          }\n        }\n      }\n    },\n    \"Zan-q8-ABi.title\" : {\n      \"comment\" : \"Class = \\\"NSWindow\\\"; title = \\\"Add Profile\\\"; ObjectID = \\\"Zan-q8-ABi\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profil hinzufügen\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Add Profile\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Agregar perfil\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ajouter un profil\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aggiungi Profilo\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"프로필 추가\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dodaj profil\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Adicionar perfil\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profil Ekle\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Додати профіль\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"پروفائل شامل کریں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"添加配置文件\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"新增設定檔\"\n          }\n        }\n      }\n    }\n  },\n  \"version\" : \"1.0\"\n}"
  },
  {
    "path": "LuLu/App/mul.lproj/Rules.xcstrings",
    "content": "{\n  \"sourceLanguage\" : \"en\",\n  \"strings\" : {\n    \"2yS-Gr-1bI.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"Label\\\"; ObjectID = \\\"2yS-Gr-1bI\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bezeichnung\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Label\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Etiqueta\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Label\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Etichetta\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"레이블\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Etykieta\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rótulo\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Etiket\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Мітка\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"لیبل\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"标签\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"標籤\"\n          }\n        }\n      }\n    },\n    \"7zm-Uo-lwv.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"Item Name\\\"; ObjectID = \\\"7zm-Uo-lwv\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Objektname\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Item Name\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nombre de Ítem\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nom d’item\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nome elemento\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"항목 이름\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nazwa elementu\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nome do Item\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Öğe Adı\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Назва елемента\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"آئٹم کا نام\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"项目名称\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"項目名稱\"\n          }\n        }\n      }\n    },\n    \"b9m-wt-VZa.title\" : {\n      \"comment\" : \"Class = \\\"NSMenuItem\\\"; title = \\\"Passively-created Rules\\\"; ObjectID = \\\"b9m-wt-VZa\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Passiv erstellte Regeln\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Passively-created Rules\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Reglas Pasivamente\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Règles créées passivement\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Regole create passivamente\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"수동으로 생성된 규칙\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pasywnie utworzone reguły\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Regras criadas passivamente\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pasif Kurallar\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Пасивно створені правила\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"حالیہ قوانین\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"被动创建的规则\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"被動建立的規則\"\n          }\n        }\n      }\n    },\n    \"cvb-ds-FcC.title\" : {\n      \"comment\" : \"Class = \\\"NSMenuItem\\\"; title = \\\"User-created Rules\\\"; ObjectID = \\\"cvb-ds-FcC\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vom Benutzer erstellte Regeln\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"User-created Rules\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Reglas del Usuario\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Règles créées par l’utilisateur\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Regole create dall'utente\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"사용자가 생성한 규칙\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Reguły utworzone przez użytkownika\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Regras criadas pelo usuário\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kullanıcı Kuralları\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Користувацькі правила\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"صارف کے قوانین\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"用户创建的规则\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"使用者建立的規則\"\n          }\n        }\n      }\n    },\n    \"DWG-ck-lDk.placeholderString\" : {\n      \"comment\" : \"Class = \\\"NSSearchFieldCell\\\"; placeholderString = \\\"Filter Rules\\\"; ObjectID = \\\"DWG-ck-lDk\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Regeln filtern\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Filter Rules\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Filtrar Reglas\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Règles de filtre\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Filtra regole\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"규칙 필터\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Reguły filtrowania\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Filtrar Regras\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kuralları süz…\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Правила фільтрації\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"قوانین فلٹر کریں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"过滤规则\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"過濾規則\"\n          }\n        }\n      }\n    },\n    \"e4i-1F-tjh.title\" : {\n      \"comment\" : \"Class = \\\"NSMenuItem\\\"; title = \\\"Recent Rules\\\"; ObjectID = \\\"e4i-1F-tjh\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Neueste Regeln\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Recent Rules\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Reglas Recientes\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Règles récentes\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Regole recenti\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"최근 규칙\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ostatnie reguły\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Regras recentes\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Son Kurallar\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Нещодавні правила\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"حالیہ قواعد\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"最近的规则\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"最近的規則\"\n          }\n        }\n      }\n    },\n    \"F0z-JX-Cv5.title\" : {\n      \"comment\" : \"Class = \\\"NSWindow\\\"; title = \\\"LuLu Rules\\\"; ObjectID = \\\"F0z-JX-Cv5\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu-Regeln\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"LuLu Rules\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Reglas de LuLu\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Règles LuLu\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Regole LuLu\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu 규칙\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Reguły LuLu\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Regras LuLu\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu Kuralları\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Правила LuLu\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"لولو قوانین\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu 规则\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu 規則\"\n          }\n        }\n      }\n    },\n    \"F7G-1t-415.label\" : {\n      \"comment\" : \"Class = \\\"NSToolbarItem\\\"; label = \\\"Custom View\\\"; ObjectID = \\\"F7G-1t-415\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Benutzerdefinierte Ansicht\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Custom View\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vista Personalizada\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vue personnalisée\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vista personalizzata\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"사용자 지정 보기\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Widok niestandardowy\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vista Customizada\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Özel Görünüm\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Кастомний вигляд\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"کاسٹم ویو\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"自定义视图\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"自訂畫面\"\n          }\n        }\n      }\n    },\n    \"F7G-1t-415.paletteLabel\" : {\n      \"comment\" : \"Class = \\\"NSToolbarItem\\\"; paletteLabel = \\\"Custom View\\\"; ObjectID = \\\"F7G-1t-415\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Benutzerdefinierte Ansicht\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Custom View\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vista Personalizada\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vue personnalisée\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vista personalizzata\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"사용자 지정 보기\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Widok niestandardowy\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vista Customizada\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Özel Görünüm\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Кастомний вигляд\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"کاسٹم ویو\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"自定义视图\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"自訂畫面\"\n          }\n        }\n      }\n    },\n    \"mQo-bf-aNx.headerCell.title\" : {\n      \"comment\" : \"Class = \\\"NSTableColumn\\\"; headerCell.title = \\\" Rule\\\"; ObjectID = \\\"mQo-bf-aNx\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \" Regel\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \" Rule\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Regla\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Règle\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Regola\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \" 규칙\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Reguła\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Regra\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kural\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Правило\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"قاعدہ\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"规则\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"規則\"\n          }\n        }\n      }\n    },\n    \"omZ-DL-6R7.title\" : {\n      \"comment\" : \"Class = \\\"NSMenuItem\\\"; title = \\\"All Rules\\\"; ObjectID = \\\"omZ-DL-6R7\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Alle Regeln\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"All Rules\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Todas las Reglas\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Toutes les règles\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tutte le regole\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"모든 규칙\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wszystkie reguły\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Todas as Regras\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tüm Kurallar\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Усі правила\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تمام قوانین\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"所有规则\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"所有規則\"\n          }\n        }\n      }\n    },\n    \"qbv-z3-4PI.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"item details...\\\"; ObjectID = \\\"qbv-z3-4PI\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Objektdetails...\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"item details...\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Detalles de ítem...\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Détails de l'item\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"dettagli elemento...\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"항목 세부 정보...\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"szczegóły elementu…\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"detalhes sobre item…\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Öğe ayrıntıları…\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"деталі елемента…\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"آئٹم کی تفصیلات...\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"项目详情\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"項目詳細資訊...\"\n          }\n        }\n      }\n    },\n    \"qNT-HP-XkH.title\" : {\n      \"comment\" : \"Class = \\\"NSMenuItem\\\"; title = \\\"Apple Rules\\\"; ObjectID = \\\"qNT-HP-XkH\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Apple-Regeln\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Apple Rules\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Reglas de Apple\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Règles Apple\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Regole Apple\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Apple 규칙\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Reguły Apple\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Regras da Apple\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Apple Kuralları\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Правила Apple\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ایپل قوانین\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Apple 规则\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Apple 規則\"\n          }\n        }\n      }\n    },\n    \"rEm-hF-r0T.title\" : {\n      \"comment\" : \"Class = \\\"NSMenuItem\\\"; title = \\\"Default Rules\\\"; ObjectID = \\\"rEm-hF-r0T\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Standardregeln\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Default Rules\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Reglas Predeterminadas\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Règles par défaut\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Regole predefinite\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"기본 규칙\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Reguły domyślne\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Regras Padrão\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Saptanmış Kurallar\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Стандартні правила\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ڈیفالٹ قوانین\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"默认规则\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"預設規則\"\n          }\n        }\n      }\n    },\n    \"tZf-9e-yHh.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"connection info\\\"; ObjectID = \\\"tZf-9e-yHh\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Verbindungsinfo\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"connection info\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"información de conexión\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"information de connection\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"informazioni connessione\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"연결 정보\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"informacje o połączeniu\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"informação sobre conexão\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"bağlantı bilgisi\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"інформація про зʼєднання\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"کنیکشن کا معلومات\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"连接信息\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"連線資訊\"\n          }\n        }\n      }\n    },\n    \"vD6-Bk-elz.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"(re)loading rules...\\\"; ObjectID = \\\"vD6-Bk-elz\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Regeln (neu)laden...\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"(re)loading rules...\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"(re)cargando reglas...\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"(re)chargement des règles ...\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"(ri)caricamento regole...\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"규칙 (재)로드 중...\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"(ponowne) ładowanie reguł…\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"(re)carregando regras…\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"kurallar (yeniden) yükleniyor…\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"(пере)завантаження правил...\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"(ری) لوڈنگ قوانین...\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"（重新）加载规则...\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"（重新）載入規則...\"\n          }\n        }\n      }\n    },\n    \"wLE-Rk-GOf.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"Add Rule\\\"; ObjectID = \\\"wLE-Rk-GOf\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Regel hinzufügen\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Add Rule\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Agregar Regla\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ajouter règle\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aggiungi regola\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"규칙 추가\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dodaj regułę\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Adicionar Regra\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kural Ekle\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Додати правило\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"قاعدہ شامل کریں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"新增规则\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"新增規則\"\n          }\n        }\n      }\n    },\n    \"YzL-Xb-QI1.title\" : {\n      \"comment\" : \"Class = \\\"NSMenuItem\\\"; title = \\\"3rd-party Rules\\\"; ObjectID = \\\"YzL-Xb-QI1\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Drittanbieterregeln\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"3rd-party Rules\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Reglas de terceros\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Règles tierce-partie\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Regole di terze parti\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"서드파티 규칙\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Reguły stron trzecich\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Regras de Terceiros\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"3. Parti Kurallar\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Правила від сторонніх постачальників\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تھرڈ پارٹی قوانین\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"第三方规则\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"第三方規則\"\n          }\n        }\n      }\n    }\n  },\n  \"version\" : \"1.0\"\n}"
  },
  {
    "path": "LuLu/App/mul.lproj/StartupWindowController.xcstrings",
    "content": "{\n  \"sourceLanguage\" : \"en\",\n  \"strings\" : {\n    \"tj8-5e-Vlc.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"Now starting up...\\\"; ObjectID = \\\"tj8-5e-Vlc\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Startet jetzt...\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Now starting up...\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Iniciando ahora...\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Démarrage en cours …\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Avvio in corso...\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"시동 중...\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Uruchamianie…\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Inicializando…\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"şimdi başlatılıyor…\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Запуск…\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"اب شروع ہو رہا ہے...\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"正在启动...\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"正在啟動...\"\n          }\n        }\n      }\n    },\n    \"XsZ-6a-7Rk.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"Note: LuLu works best on macOS 15.3+, as Apple fixed bugs affecting network stability. \\\"; ObjectID = \\\"XsZ-6a-7Rk\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hinweis: LuLu funktioniert am besten unter macOS 15.3+, da Apple Fehler behoben hat, die die Netzwerkstabilität beeinträchtigten.\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Note: LuLu works best on macOS 15.3+, as Apple fixed bugs affecting network stability. \"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nota: LuLu funciona mejor en macOS 15.3+, ya que Apple corrigió errores que afectaban la estabilidad de la red.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Remarque : LuLu fonctionne mieux sur macOS 15.3+, car Apple a corrigé des bugs affectant la stabilité du réseau.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nota: LuLu funziona al meglio su macOS 15.3+, poiché Apple ha corretto bug che influivano sulla stabilità della rete.\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"참고: LuLu는 macOS 버전 15.3 이상에 최적화되었습니다. 이는 Apple이 네트워크 안정성에 영향을 주는 버그를 수정했기 때문입니다.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Uwaga: LuLu działa najlepiej na macOS 15.3+, ponieważ Apple naprawiło błędy wpływające na stabilność sieci.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nota: O LuLu funciona melhor no macOS 15.3+, pois a Apple corrigiu bugs que afetavam a estabilidade da rede.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Not: LuLu, macOS 15.3+ üzerinde en iyi şekilde çalışır, çünkü Apple ağ kararlılığını etkileyen hataları düzeltti.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Примітка: LuLu найкраще працює на macOS 15.3+, оскільки Apple виправила помилки, що впливали на стабільність мережі.\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"نوٹ: لولو macOS 15.3+ پر بہترین کام کرتا ہے، کیونکہ ایپل نے نیٹ ورک کی استحکام کو متاثر کرنے والے بگز کو ٹھیک کیا ہے۔\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"注意：LuLu 在 macOS 15.3+ 上运行效果最佳，因为 Apple 修复了影响网络稳定性的错误。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"注意：由於 Apple 修復了影響網路穩定性的錯誤，LuLu 在 macOS 15.3+ 上運作最佳。\"\n          }\n        }\n      }\n    }\n  },\n  \"version\" : \"1.0\"\n}"
  },
  {
    "path": "LuLu/App/mul.lproj/StatusBarPopover.xcstrings",
    "content": "{\n  \"sourceLanguage\" : \"en\",\n  \"strings\" : {\n    \"2jG-uf-4XV.title\" : {\n      \"comment\" : \"Class = \\\"NSButtonCell\\\"; title = \\\"⌃\\\"; ObjectID = \\\"2jG-uf-4XV\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌃\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"⌃\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌃\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"^\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌃\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌃\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"^\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌃\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌃\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌃\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌃\"\n          }\n        }\n      },\n      \"shouldTranslate\" : false\n    },\n    \"17.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"LuLu up & running!\\\"; ObjectID = \\\"17\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu läuft!\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"LuLu up & running!\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"¡LuLu en funcionamiento!\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu est opérationnel !\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu è attivo e funzionante!\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu 정상 작동 중!\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu jest uruchomiona!\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu está rodando!\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu açık ve çalışıyor!\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu запущено і працює!\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"!لولو چل رہا ہے\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu 已启动并运行中！\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu 已啟動並執行中！\"\n          }\n        }\n      }\n    },\n    \"22.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"Access it from here anytime.\\\"; ObjectID = \\\"22\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Greife jederzeit von hier aus darauf zu.\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Access it from here anytime.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Acceda desde aquí en cualquier momento.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Accédez-y ici à tout moment\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Accedici da qui in qualsiasi momento.\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"언제든 여기서 이용할 수 있습니다.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dostęp możesz uzyskać w dowolnym momencie stąd.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Acesse-o daqui quando quiser.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ona buradan istediğiniz zaman erişebilirsiniz.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Отримуйте доступ до нього звідси в будь-який час.\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"کسی بھی وقت یہاں سے اس تک رسائی حاصل کریں۔\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"可随时从这里访问。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"隨時可以從這裡存取。\"\n          }\n        }\n      }\n    }\n  },\n  \"version\" : \"1.0\"\n}"
  },
  {
    "path": "LuLu/App/mul.lproj/UpdateWindow.xcstrings",
    "content": "{\n  \"sourceLanguage\" : \"en\",\n  \"strings\" : {\n    \"F0z-JX-Cv5.title\" : {\n      \"comment\" : \"Class = \\\"NSWindow\\\"; title = \\\"LuLu Update\\\"; ObjectID = \\\"F0z-JX-Cv5\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu Update\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"LuLu Update\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Actualizar LuLu\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mise à jour de LuLu\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aggiornamento LuLu\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu 업데이트\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aktualizacja LuLu\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Atualização LuLu\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu’yu Güncelle\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Оновлення LuLu\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"لولو اپڈیٹ\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu 更新\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu 更新\"\n          }\n        }\n      }\n    },\n    \"nMV-1f-RyK.title\" : {\n      \"comment\" : \"Class = \\\"NSButtonCell\\\"; title = \\\"Update\\\"; ObjectID = \\\"nMV-1f-RyK\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Update\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Update\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Actualizar\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mettre à jour\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aggiorna\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"업데이트\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aktualizuj\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Atializar\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Güncelle\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Оновити\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"اپڈیٹ\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"更新\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"更新\"\n          }\n        }\n      }\n    }\n  },\n  \"version\" : \"1.0\"\n}"
  },
  {
    "path": "LuLu/App/mul.lproj/Welcome.xcstrings",
    "content": "{\n  \"sourceLanguage\" : \"en\",\n  \"strings\" : {\n    \"3aO-AI-YtY.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"Outgoing connections from currently installed 3rd-party programs will be allowed.\\\"; ObjectID = \\\"3aO-AI-YtY\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Diese Option erlaub allen bereits installierten Drittanbieterprogrammen auf das Netzwerk zugreifen, ohne eine Mitteilung auszulösen.\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Outgoing connections from currently installed 3rd-party programs will be allowed.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Esta opción permitirá que cualquier aplicación de terceros que ya esté instalada acceda a la red sin generar una alerta.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Cette option permet à toute application tierce déjà installée d'accéder au réseau sans générer d'alerte.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Questa opzione consentirà a qualsiasi app di terze parti già installata di accedere alla rete senza generare un avviso.\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"이 옵션은 이전에 설치한 모든 타사 프로그램을 허용합니다. 해당 프로그램은 경고 발생 없이 네트워크에 접근할 수 있습니다.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Opcja ta umożliwi każdej zainstalowanej już aplikacji innej firmy dostęp do sieci bez generowania alertu.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Esta opção permitirá que qualquer aplicativo de terceiros que já esteja instalado tenha acesso à rede sem gerar um alerta.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Bu seçenek, halihazırda kurulu olan herhangi bir 3. parti uygulamanın bir ikâz oluşturmadan ağa erişimine izin verir.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Ця опція дозволить будь-якому сторонньому додатку, який уже встановлено, отримувати доступ до мережі без сповіщення.\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"یہ آپشن کسی بھی پہلے سے انسٹال شدہ تھرڈ پارٹی ایپ کو الرٹ پیدا کیے بغیر نیٹ ورک تک رسائی کی اجازت دے گا۔\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"此选项将允许任何已安装的第三方应用程序访问网络而不会生成警报。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"這個選項將允許任何已安裝的第三方應用程式存取網路，而不會產生警告。\"\n          }\n        }\n      }\n    },\n    \"7pD-BH-c8i.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"Mahalo to the \\\\\\\"Friends Objective-See\\\\\\\"\\\"; ObjectID = \\\"7pD-BH-c8i\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mahalo an die \\\"Friends Objective-See\\\"\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Mahalo to the \\\"Friends Objective-See\\\"\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gracias a los \\\"Friends of Objective-See\\\"\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mahalo aux « Amis Objectif-See »\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Grazie agli \\\"Amici di Objective-See\\\"\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"\\\"Objective-See 친구들\\\"에게, 마할로!\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mahalo do „Przyjaciół Objective-See”\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mahalo para os “Amigos Objective-See\\\"\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"“Objective-See” Arkadaşlarına Mahalo\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Дякуємо «Friends Objective-See»\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"\\\"Objective-See دوستوں\\\" کو شکریہ\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"感谢“Objective-See 的伙伴们”\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"感謝「Objective-See 的朋友」\"\n          }\n        }\n      }\n    },\n    \"8KH-RD-y9L.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"Note: steps may vary by macOS version\\\"; ObjectID = \\\"8KH-RD-y9L\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Note: steps may vary by macOS version\"\n          }\n        }\n      }\n    },\n    \"C1V-iy-oEo.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"1. In the \\\\\\\"System Extension Blocked\\\\\\\" alert, click: \\\\\\\"Open System Settings\\\\\\\"\\\"; ObjectID = \\\"C1V-iy-oEo\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"1. Auf der „Systemerweiterung blockiert“-Meldung drücke: „Systemeinstellungen öffnen“.\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"1. In the \\\"System Extension Blocked\\\" alert, click: \\\"Open System Settings\\\"\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"1. En la alerta \\\"Extensión de Sistema Bloqueada\\\", haga click en: \\\"Abrir Configuración del Sistema\\\"\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"1. Dans l'alerte « Extension du système bloquée », cliquez sur : « Ouvrir les Réglages Système »\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"1. Nell’avviso \\\"Estensione di sistema bloccata\\\", fai clic su: \\\"Apri Impostazioni di sistema\\\"\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"1. \\\"새로운 네트워크 확장 프로그램\\\" 경고 대화상자에서 \\\"시스템 설정 열기\\\"를 클릭합니다\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"1. W alercie „Zablokowane rozszerzenie systemu” kliknij: „Otwórz ustawienia systemu”\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"1. No alerta de “Extensão do Sistema Bloqueada”, clique em “Abrir Preferências do Sistema”\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"1. “Sistem Genişletmesi Engellendi” ikâzında “Sistem Ayarları’nı Aç”a tıklayın.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"1. У сповіщенні «Системне розширення заблоковано» натисніть «Відкрити системні параметри».\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"1. \\\"سسٹم ایکسٹینشن بلاک\\\" الرٹ میں، کلک کریں: \\\"سسٹم سیٹنگز کھولیں\\\"\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"1. 在“系统扩展被阻止”警报中，单击：“打开系统设置”\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"1. 在「已封鎖的系統延伸功能」的警示中，按下「開啟系統設定」\"\n          }\n        }\n      }\n    },\n    \"Cwe-NI-HiJ.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"First,  allow the LuLu Network Extension:\\\"; ObjectID = \\\"Cwe-NI-HiJ\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zuerst muss die LuLu Netzwerkerweiterung zugelassen werden:\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"First,  allow the LuLu Network Extension:\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Primero, permite la Extensión de Red de LuLu:\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tout d'abord, autorisez l'extension de réseau LuLu :\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Per prima cosa, consenti l’Estensione di rete di LuLu:\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"먼저,  LuLu 네트워크 확장 프로그램을 허용합니다:\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Najpierw zezwól na rozszerzenie sieciowe LuLu:\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Primeiro, dê permissão à Extensão de Rede LuLu\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Öncelikle, LuLu ağ genişletmesine izin verin:\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Спочатку, надайте доступ розширенню LuLu:\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"پہلے، LuLu نیٹ ورک ایکسٹینشن کو اجازت دیں:\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"首先，允许 LuLu 网络扩展：\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"首先，允許 LuLu 網路延伸功能：\"\n          }\n        }\n      }\n    },\n    \"eic-lg-Ln7.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"It monitors network activity and alerts you when a program first tries to initiate an outgoing connection, allowing you to permit or deny it.\\\"; ObjectID = \\\"eic-lg-Ln7\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Überwacht die Netzwerkaktivität und warnt, wenn ein Programm zum ersten Mal versucht, eine ausgehende Verbindung herzustellen, sodass diese erlaubt oder blockiert werden kann.\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"It monitors network activity and alerts you when a program first tries to initiate an outgoing connection, allowing you to permit or deny it.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Monitorea la actividad de la red y alerta cuando un programa intenta iniciar por primera vez una conexión saliente, permitiéndote permitirla o denegarla.  \"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Il surveille l'activité du réseau et vous avertit lorsqu'un programme tente pour la première fois d'établir une connexion sortante, ce qui vous permet de l'autoriser ou de la refuser.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Per prima cosa, consenti l’Estensione di rete di LuLu:\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"네트워크 활동을 모니터하고, 어떤 프로그램이 나가는 연결을 최초로 시도할 때 사용자가 허용하거나 거부할 수 있도록 경고합니다.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Monitoruje aktywność sieciową i powiadamia Cię, gdy program po raz pierwszy próbuje zainicjować połączenie wychodzące, umożliwiając Ci zezwolenie na nie lub jego zablokowanie.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ele monitora a atividade na rede e te alerta quando um programa tenta iniciar uma conexão de saída, lhe permitindo que possa autorizá-la ou não.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ağ etkinliğinizi izler ve bir program ilk kez dışarıya bir bağlantı sağlamaya çalıştığında sizi ikâz eder ve izin vermenizi veya engellemenizi ister.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Вона відстежує мережеву активність і сповіщає вас, коли програма вперше намагається ініціювати вихідне з'єднання, тож ви зможете його дозволити або заборонити.\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"یہ نیٹ ورک کی سرگرمیوں کو مانیٹر کرتا ہے اور آپ کو الرٹ کرتا ہے جب کوئی پروگرام پہلی بار باہر کی طرف کنیکشن قائم کرنے کی کوشش کرتا ہے، آپ کو اجازت دینے یا انکار کرنے کی اجازت دیتا ہے۔\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"它监视网络活动，并在程序首次尝试启动传出连接时发出警报，以便您允许或拒绝它。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"當程式首次嘗試建立對外連線時，它會監控網路活動並向您發出警告，讓您可以允許或拒絕連線。\"\n          }\n        }\n      }\n    },\n    \"EOD-Hh-8e5.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"...\\\"; ObjectID = \\\"EOD-Hh-8e5\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"...\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"…\"\n          }\n        }\n      },\n      \"shouldTranslate\" : false\n    },\n    \"F0z-JX-Cv5.title\" : {\n      \"comment\" : \"Class = \\\"NSWindow\\\"; title = \\\"LuLu\\\"; ObjectID = \\\"F0z-JX-Cv5\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"LuLu\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu\"\n          }\n        }\n      },\n      \"shouldTranslate\" : false\n    },\n    \"NCu-fH-K04.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"These can be changed later, via LuLu's Settings.\\\"; ObjectID = \\\"NCu-fH-K04\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"These can be changed later, via LuLu's Settings.\"\n          }\n        }\n      }\n    },\n    \"pMo-Yj-XKY.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"LuLu is a free open-source firewall for macOS.\\\"; ObjectID = \\\"pMo-Yj-XKY\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lulu ist eine freie quelloffene Firewall für macOS\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"LuLu is a free open-source firewall for macOS.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu es un firewall gratuito y open-source para macOS.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu est un pare-feu libre et gratuit pour macOS.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu è un firewall gratuito e open-source per macOS.\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu는 macOS를 위한 무료 오픈소스 방화벽입니다.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu to darmowa zapora sieciowa typu open source dla systemu macOS.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu é um firewall gratuito e open-source para macOS.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu, macOS için ücretsiz ve açık kaynak bir güvenlik duvarıdır.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu — це безкоштовний фаєрвол із відкритим кодом для macOS.\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu ایک مفت اوپن سورس فائر وال ہے جو macOS کے لیے ہے۔\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu 是一款适用于 macOS 的免费开源防火墙。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu 是一款用於 macOS 的免費開源防火牆。\"\n          }\n        }\n      }\n    },\n    \"QA3-Ww-PeC.title\" : {\n      \"comment\" : \"Class = \\\"NSButtonCell\\\"; title = \\\"No\\\"; ObjectID = \\\"QA3-Ww-PeC\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nein\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"No\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"No\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Non\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"No\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"아니요\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nie\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Não\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hayır\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ні\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"نہیں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"否\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"否\"\n          }\n        }\n      }\n    },\n    \"qNj-Zh-8FW.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"Support LuLu?\\\"; ObjectID = \\\"qNj-Zh-8FW\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu unterstützen?\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Support LuLu?\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"¿Apoyas a LuLu?\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Soutenir LuLu ?\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vuoi supportare LuLu?\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu를 응원하시겠어요?\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wesprze\\u0003ć LuLu?\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Apoiar o LuLu?\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu’yu desteklemek ister misiniz?\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Підтримати LuLu?\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"کیا آپ LuLu کی مدد کرنا چاہتے ہیں؟\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"支持LuLu吗？\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"支持 LuLu？\"\n          }\n        }\n      }\n    },\n    \"qYE-G3-j1K.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"4. In the \\\\\\\"Filter Network Content\\\\\\\" alert, click: \\\\\\\"Allow\\\\\\\"\\\"; ObjectID = \\\"qYE-G3-j1K\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"4. Klicke in dem Hinweis „Netzwerkinhalte filtern“ auf: „Erlauben“\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"4. In the \\\"Filter Network Content\\\" alert, click: \\\"Allow\\\"\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"4. En la alerta \\\"Filtrar Contenido de Red\\\", haga click en: \\\"Permitir\\\"\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"4. Dans l'alerte « Filtrer le contenu du réseau », cliquez sur : « Autoriser »\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"4. Nell’avviso \\\"Filtra contenuti di rete\\\", fai clic su: \\\"Consenti\\\"\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"4. \\\"네트워크 콘텐츠 필터링\\\" 경고 대화상자에서 \\\"허용\\\"을 클릭합니다\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"4. W alercie „Filtruj zawartość sieciową” kliknij: „Zezwól”\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"4. No alerta de “Filtrar Conteúdo de Rede”, clique em “Permitir”\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"4. “Ağ İçeriğini Filtrele” ikâzında “İzin Ver”e tıklayın.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"4. У сповіщенні «Фільтрувати мережевий контент» натисніть «Дозволити».\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"4. \\\"نیٹ ورک مواد کو فلٹر کریں\\\" الرٹ میں، کلک کریں: \\\"اجازت دیں\\\"\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"4. 在“过滤网络内容”警告中，点击“允许”\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"4. 在「過濾網路內容」的警告中，按下「允許」\"\n          }\n        }\n      }\n    },\n    \"Qyh-uK-Afv.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"Welcome to\\\"; ObjectID = \\\"Qyh-uK-Afv\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Willkommen zu\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Welcome to\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bienvenido a \"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bienvenue sur\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Benvenuto in\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"반가워요!\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Witamy w\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bem-vindo ao\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hoş Geldiniz\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ласкаво просимо до\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"خوش آمدید\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"欢迎使用\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"歡迎使用\"\n          }\n        }\n      }\n    },\n    \"r1b-Nl-Ii7.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"Outgoing connections from Apple-signed programs will be allowed.\\\"; ObjectID = \\\"r1b-Nl-Ii7\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Diese Option erlaubt allen von Apple signierten Programmen auf das Netzwerk zuzugreifen, ohne eine Mitteilung auszulösen.\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Outgoing connections from Apple-signed programs will be allowed.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Esta opción permitirá que cualquier código binario firmado por Apple acceda a la red sin generar una alerta.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Cette option permet à tout binaire signé par Apple d'accéder au réseau sans générer d'alerte.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Questa opzione consentirà a qualsiasi binario firmato da Apple di accedere alla rete senza generare un avviso.\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"이 옵션을 활성화하면 Apple에 의해 서명된 실행 파일을 허용합니다. 해당 프로그램은 경고 발생 없이 네트워크에 접근할 수 있습니다.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Ta opcja umożliwi dostęp do sieci każdemu plikowi binarnemu podpisanemu przez Apple bez generowania alertu.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Esta permissão permitirá que qualquer binário assinado pela Apple tenha acesso à rede sem gerar um alerta.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Bu seçenek, Apple tarafından imzalanmış herhangi bir ikilinin, bir ikâz oluşturmadan ağa erişimine izin verecektir.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Ця опція дозволить будь-якому бінарному файлу, підписаному Apple, отримувати доступ до мережі без сповіщення.\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"یہ آپشن کسی بھی ایپل سائنڈ بائنری کو الرٹ پیدا کیے بغیر نیٹ ورک تک رسائی کی اجازت دے گا۔\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"此选项将允许任何 Apple 签名的二进制文件访问网络而不会生成警报。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"此選項將允許任何由 Apple 簽署的程式存取網路，而不會產生警告。\"\n          }\n        }\n      }\n    },\n    \"Re5-aD-QVR.title\" : {\n      \"comment\" : \"Class = \\\"NSButtonCell\\\"; title = \\\"Yes!\\\"; ObjectID = \\\"Re5-aD-QVR\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ja!\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Yes!\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"¡Sí!\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Oui !\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sì!\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"좋아요!\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tak!\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sim!\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Evet!\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Так!\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"جی!\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"是！\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"是！\"\n          }\n        }\n      }\n    },\n    \"sAE-Mf-3fz.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"All outgoing UDP traffic on port 53 will be allowed.\\\"; ObjectID = \\\"sAE-Mf-3fz\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Diese Option erlaubt alle (UDP-) Verbindungen auf Port 53.\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"All outgoing UDP traffic on port 53 will be allowed.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Esta opción permitirá cualquier tráfico (UDP) sobre el puerto 53. \"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Cette option autorise tout trafic (UDP) sur le port 53.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Questa opzione consentirà qualsiasi traffico (UDP) sulla porta 53.\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"이 옵션을 활성화하면 53번 포트를 통하는 모든 (UDP) 트래픽을 허용합니다.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Opcja ta zezwoli na cały ruch (UDP) przez port 53.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Esta opção permitirá qualquer tráfego (UDP) na porta 53.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Bu seçenek, 53. kapı üzerinden herhangi bir UDP trafiğine izin verecektir.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Ця опція дозволить будь-який (UDP) трафік через порт 53.\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"یہ آپشن کسی بھی (UDP) ٹریفک کو پورٹ 53 پر اجازت دے گا۔\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"此选项将允许通过端口 53 的任何 (UDP) 流量。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"此選項將允許任何連接埠 53 的（UDP）流量。\"\n          }\n        }\n      }\n    },\n    \"SWc-iv-oN4.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\" Allow DNS Traffic\\\"; ObjectID = \\\"SWc-iv-oN4\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \" DNS-Verbindungen erlauben\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \" Allow DNS Traffic\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Permitir Tráfico DNS\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Autoriser le trafic DNS\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Consenti traffico DNS\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \" DNS 트래픽 허용\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zezwól na ruch DNS\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Permitir tráfego de DNS\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"DNS trafiğine izin ver\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Дозволити DNS трафік\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"DNS ٹریفک کو اجازت دیں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"允许 DNS 流量\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"允許 DNS 流量\"\n          }\n        }\n      }\n    },\n    \"Uzd-7P-dzG.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"It's free, open-source, and written by a single (Mac-loving) coder!\\\"; ObjectID = \\\"Uzd-7P-dzG\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Es ist frei, quelloffen und von einem einzigen (Mac-liebenden) Entwickler geschrieben! \"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"It's free, open-source, and written by a single (Mac-loving) coder!\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sin cargo, open-source y desarrollado por un único programador (amante de Mac)!  \"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"C’est gratuit, open-source et écrit par un seul codeur (amoureux du Mac) !\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"È gratuito, open-source e scritto da un singolo programmatore (innamorato del Mac)!\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"무료이면서, 오픈소스에, 한 (Mac 덕후) 코더에 의해 개발되었습니다!\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Jest darmowy, ma otwarte oprogramowanie i został napisany przez jednego (miłośnika Maców) programistę!\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"É gratuito, open-source, e criado por um único programador (amante de Mac)!\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ücretsizdir, açık kaynaktır ve tek bir (Mac hastası) kodcu tarafından yazılmıştır!\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Безкоштовна, з відкритим кодом, створена однією людиною.\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"یہ مفت ہے، اوپن سورس ہے اور ایک ہی (میک لوونگ) کوڈر نے لکھا ہے!\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"它是免费的、开源的，并且是由一位（热爱 Mac 的）程序员编写的！\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"這是一款免費、開源的軟體，由一位（熱愛 Mac的）程式設計師所開發！\"\n          }\n        }\n      }\n    },\n    \"VIe-9o-Kc7.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"Waiting for System Extension Approval\\\"; ObjectID = \\\"VIe-9o-Kc7\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Warten auf die Genehmigung der Systemerweiterung\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Waiting for System Extension Approval\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Esperando Aprobación de la Extensión del Sistema\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"En attente de l'approbation de l'extension du système\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"In attesa dell’approvazione dell’estensione di sistema\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"시스템 확장 프로그램 승인 대기 중\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Oczekiwanie na zatwierdzenie rozszerzenia systemu\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Esperando aprovação da extensão do sistema\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sistem Genişletmesi Onayı Bekleniyor\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Очікується схвалення системного розширення\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"سیسٹم ایکسٹینشن کی منظوری کا انتظار\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"等待系统扩展批准\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"正在等待系統延伸功能被核准\"\n          }\n        }\n      }\n    },\n    \"XBE-gW-YkK.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"Show some love? \\\"; ObjectID = \\\"XBE-gW-YkK\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ein bisschen Liebe zeigen?\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Show some love? \"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"¿Nos das tu apoyo?\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Montrer un peu d’amour ?\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vuoi mostrare un po’ di supporto?\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"애정을 보여주실래요?\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Okażesz trochę miłości?\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dar carinho?\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Biraz sevgi gösterseniz?\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Бажаєте підтримати?\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"کیا آپ ہمیں پیار دکھانا چاہتے ہیں؟\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"表达一些支持？\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"要表達一些支持嗎？\"\n          }\n        }\n      }\n    },\n    \"xbU-XH-hYT.title\" : {\n      \"comment\" : \"Class = \\\"NSButtonCell\\\"; title = \\\"Next\\\"; ObjectID = \\\"xbU-XH-hYT\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Weiter\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Next\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Siguiente\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Suivant\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Avanti\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"다음\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dalej\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Próximo\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sonraki\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Далі\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"اگلا\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"下一步\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"下一步\"\n          }\n        }\n      }\n    },\n    \"XHD-XH-wR0.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"Now, let's configure LuLu:\\\"; ObjectID = \\\"XHD-XH-wR0\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nun wollen wir LuLu konfigurieren:\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Now, let's configure LuLu:\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ahora, configuremos LuLu:\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Maintenant, configurons LuLu :\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ora configuriamo LuLu:\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"자, LuLu를 구성해봅시다:\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Teraz skonfigurujmy LuLu:\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Agora vamos configurar o LuLu:\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Haydi LuLu’yu yapılandıralım:\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"А тепер давайте налаштуємо LuLu:\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"اب، ہم LuLu کو تشکیل دیں:\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"现在，让我们配置 LuLu：\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"現在，讓我們來設定 LuLu：\"\n          }\n        }\n      }\n    },\n    \"ymJ-tB-qiA.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\" Allow Already Installed Programs\\\"; ObjectID = \\\"ymJ-tB-qiA\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \" Bereits installierte Anwendungen erlauben\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \" Allow Already Installed Programs\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Permitir Aplicaciones Ya Instaladas\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Autoriser les applications déjà installées\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Consenti applicazioni già installate\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \" 사전에 설치된 프로그램 허용\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Zezwalaj na już zainstalowane aplikacje\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Permitir aplicações já instaladas\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Halihazırda kurulu uygulamalara izin ver\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"Дозволити вже установлені програми\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"پہلے سے انسٹال شدہ ایپلی کیشنز کو اجازت دیں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"允许已安装的应用程序\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"needs_review\",\n            \"value\" : \"允許已安裝的應用程式\"\n          }\n        }\n      }\n    },\n    \"YXa-F3-XSG.title\" : {\n      \"comment\" : \"Class = \\\"NSButtonCell\\\"; title = \\\"Next\\\"; ObjectID = \\\"YXa-F3-XSG\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Weiter\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Next\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Siguiente\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Suivant\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Avanti\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"다음\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dalej\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Próximo\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sonraki\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Далі\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"اگلا\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"下一步\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"下一步\"\n          }\n        }\n      }\n    },\n    \"zo1-a0-tPg.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\" Allow Apple Programs\\\"; ObjectID = \\\"zo1-a0-tPg\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \" Apple-Programme erlauben\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \" Allow Apple Programs\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Permitir Programas de Apple\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Autoriser les programmes Apple\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Consenti programmi Apple\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \" Apple 프로그램 허용\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zezwalaj na programy Apple\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Permitir programas Apple\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Apple programlarına izin ver\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Дозволити програми Apple\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ایپل پروگرامز کو اجازت دیں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"允许 Apple 程序\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"允許 Apple 程式\"\n          }\n        }\n      }\n    },\n    \"ZZK-2G-iIB.title\" : {\n      \"comment\" : \"Class = \\\"NSTextFieldCell\\\"; title = \\\"3. Authenticate\\\"; ObjectID = \\\"ZZK-2G-iIB\\\";\",\n      \"extractionState\" : \"extracted_with_value\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"3. Authentifiziere\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"3. Authenticate\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"3. Autenticar\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"3. S’authentifier\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Autenticati\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"3. 인증합니다\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"3. Uwierzytelnij\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"3. Autenticar\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"3. Yetkilendirin.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"3. Аутентифікувати\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"3. تصدیق کریں۔\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"3. 身份验证\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"3. 進行驗證\"\n          }\n        }\n      }\n    }\n  },\n  \"version\" : \"1.0\"\n}"
  },
  {
    "path": "LuLu/App/patrons.txt",
    "content": "Patrons (2^6+):\nJan Koum, Matt Mullenweg, Christian Blümlein, Shain Singh, Andreas Fink, Nuno, Rabi Rob Thomas, Mikhail S.\n\nFriends of Objective-See:\nKandji, Fleet, Jamf, Moonlock, Palo Alto Networks, Sophos, Malwarebytes, iVerify, Huntress, SmugMug, Guardian Mobile Firewall, Halo Privacy, The Mitten Mac\n"
  },
  {
    "path": "LuLu/Extension/Alerts.h",
    "content": "//\n//  file: Alerts.h\n//  project: lulu (launch daemon)\n//  description: alert related logic/tracking (header)\n//\n//  created by Patrick Wardle\n//  copyright (c) 2017 Objective-See. All rights reserved.\n//\n\n\n@import OSLog;\n@import Foundation;\n@import NetworkExtension;\n\n#import \"Process.h\"\n#import \"XPCUserProto.h\"\n#import \"XPCUserClient.h\"\n\n@interface Alerts : NSObject\n\n/* PROPERTIES */\n\n//shown alerts\n@property(nonatomic, retain)NSMutableDictionary* shownAlerts;\n\n\n//xpc client for talking to user (login item)\n@property(nonatomic, retain)XPCUserClient* xpcUserClient;\n\n//console user\n@property(nonatomic, retain)NSString* consoleUser;\n\n/* METHODS */\n\n//create an alert object\n-(NSMutableDictionary*)create:(NEFilterSocketFlow*)flow process:(Process*)process;\n\n//via XPC, send an alert\n-(BOOL)deliver:(NSDictionary*)alert reply:(void (^)(NSDictionary*))reply;\n\n//is related to a shown alert?\n// checks if path/signing info is same\n-(BOOL)isRelated:(Process*)process;\n\n//add an alert to 'shown'\n-(void)addShown:(NSDictionary*)alert;\n\n//remove an alert from 'shown'\n-(void)removeShown:(NSDictionary*)alert;\n\n@end\n"
  },
  {
    "path": "LuLu/Extension/Alerts.m",
    "content": "//\n//  file: Alerts.m\n//  project: lulu (launch daemon)\n//  description: alert related logic/tracking\n//\n//  created by Patrick Wardle\n//  copyright (c) 2017 Objective-See. All rights reserved.\n//\n\n#import \"consts.h\"\n#import \"Process.h\"\n#import \"Alerts.h\"\n#import \"utilities.h\"\n\n/* GLOBALS */\n\n//log handle\nextern os_log_t logHandle;\n\n@implementation Alerts\n\n@synthesize shownAlerts;\n@synthesize consoleUser;\n@synthesize xpcUserClient;\n\n//init\n-(id)init\n{\n    //super\n    self = [super init];\n    if(nil != self)\n    {\n        //alloc shown\n        shownAlerts = [NSMutableDictionary dictionary];\n        \n        //init user xpc client\n        xpcUserClient = [[XPCUserClient alloc] init];\n    }\n    \n    return self;\n}\n\n//create an alert dictionary\n-(NSMutableDictionary*)create:(NEFilterSocketFlow*)flow process:(Process*)process\n{\n    //event for alert\n    NSMutableDictionary* alert = nil;\n    \n    //remote endpoint\n    NWHostEndpoint* remoteEndpoint = nil;\n    \n    //alloc\n    alert = [NSMutableDictionary dictionary];\n    \n    //add uuid\n    alert[KEY_UUID] = [[NSUUID UUID] UUIDString];\n    \n    //add key\n    alert[KEY_KEY] = process.key;\n    \n    //extract remote endpoint\n    remoteEndpoint = (NWHostEndpoint*)flow.remoteEndpoint;\n    \n    //add pid\n    alert[KEY_PROCESS_ID] = [NSNumber numberWithUnsignedInt:process.pid];\n    \n    //add args\n    if(0 != process.arguments.count)\n    {\n        //add\n        alert[KEY_PROCESS_ARGS] = process.arguments;\n    }\n    \n    //add path\n    alert[KEY_PATH] = process.path;\n    \n    //add name\n    alert[KEY_PROCESS_NAME] = process.name;\n\n    //add process state\n    if(YES == process.deleted)\n    {\n        //add\n        alert[KEY_PROCESS_DELETED] = @YES;\n    }\n    \n    //process ancestors?\n    // ...only add if more than just self\n    if(process.ancestors.count > 1)\n    {\n        //add\n        alert[KEY_PROCESS_ANCESTORS] = process.ancestors;\n    }\n    \n    //add (remote) ip\n    alert[KEY_HOST] = remoteEndpoint.hostname;\n    \n    //add (remote) host\n    // as string though, since XPC doesn't like NSURLs\n    if(nil != flow.URL)\n    {\n        //add\n        alert[KEY_URL] = flow.URL.absoluteString;\n    }\n        \n    //add (remote) port\n    alert[KEY_ENDPOINT_PORT] = remoteEndpoint.port;\n    \n    //add protocol\n    alert[KEY_PROTOCOL] = [NSNumber numberWithInt:flow.socketProtocol];\n\n    //add signing info\n    if(nil != process.csInfo)\n    {\n        //add\n        alert[KEY_CS_INFO] = process.csInfo;\n    }\n\n    return alert;\n}\n\n//is related to a shown alert?\n// checks if path/signing info is same\n-(BOOL)isRelated:(Process*)process\n{\n    //flag\n    __block BOOL related = NO;\n    \n    //alert\n    NSDictionary* alert = nil;\n    \n    //sync\n    @synchronized(self.shownAlerts)\n    {\n        //grab alert\n        // none, means its new\n        alert = self.shownAlerts[process.key];\n        if(nil == alert)\n        {\n            //bail\n            goto bail;\n        }\n        \n        //related\n        related = YES;\n    \n    }//sync\n    \nbail:\n    \n    return related;\n}\n\n//add an alert to 'shown'\n-(void)addShown:(NSDictionary*)alert\n{\n    //dbg msg\n    os_log_debug(logHandle, \"adding alert to 'shown': %{public}@ -> %{public}@\", alert[KEY_KEY], alert);\n    \n    //add alert\n    @synchronized(self.shownAlerts)\n    {\n        //add\n        self.shownAlerts[alert[KEY_KEY]] = alert;\n    }\n    \n    return;\n}\n\n//remove an alert from 'shown'\n-(void)removeShown:(NSDictionary*)alert\n{\n    //dbg msg\n    os_log_debug(logHandle, \"removing alert from 'shown': %{public}@ -> %{public}@\", alert[KEY_KEY], alert);\n    \n    //remove alert\n    @synchronized(self.shownAlerts)\n    {\n        //remove\n        [self.shownAlerts removeObjectForKey:alert[KEY_KEY]];\n    }\n    \n    return;\n}\n\n//via XPC, send an alert to the client (user)\n-(BOOL)deliver:(NSDictionary*)alert reply:(void (^)(NSDictionary*))reply\n{\n    //flag\n    BOOL delivered = NO;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"delivering alert %{public}@\", alert);\n    \n    //send via XPC to user\n    if(YES != (delivered = [self.xpcUserClient deliverAlert:alert reply:reply]))\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: failed to deliver alert to user (no client?)\");\n        \n        //bail\n        goto bail;\n    }\n\nbail:\n    \n    return delivered;\n}\n\n@end\n"
  },
  {
    "path": "LuLu/Extension/Binary.h",
    "content": "//\n//  Binary.h\n//  LuLu\n//\n//  Created by Patrick Wardle on 8/27/20.\n//  Copyright (c) 2020 Objective-See. All rights reserved.\n//\n\n#ifndef Binary_h\n#define Binary_h\n\n#import \"Consts.h\"\n#import \"signing.h\"\n#import \"utilities.h\"\n\n@import OSLog;\n@import CommonCrypto;\n\n@interface Binary : NSObject\n{\n    \n}\n\n/* PROPERTIES */\n\n//path\n@property(nonatomic, retain)NSString* _Nonnull path;\n\n//name\n@property(nonatomic, retain)NSString* _Nonnull name;\n\n//icon\n@property(nonatomic, retain)NSImage* _Nonnull icon;\n\n//file attributes\n@property(nonatomic, retain)NSDictionary* _Nullable attributes;\n\n//spotlight meta data\n@property(nonatomic, retain)NSDictionary* _Nullable metadata;\n\n//bundle\n// nil for non-apps\n@property(nonatomic, retain)NSBundle* _Nullable bundle;\n\n//signing info\n@property(nonatomic, retain)NSMutableDictionary* _Nonnull csInfo;\n\n//hash\n@property(nonatomic, retain)NSMutableString* _Nonnull sha256;\n\n/* METHODS */\n\n//init w/ a path\n-(id _Nonnull)init:(NSString* _Nonnull)path;\n\n/* the following methods are rather CPU-intensive\n   as such, if the proc monitoring is run with the 'goEasy' option, they aren't automatically invoked\n*/\n \n//get an icon for a process\n// for apps, this will be app's icon, otherwise just a standard system one\n-(void)getIcon;\n\n//generate signing info (statically)\n-(void)generateSigningInfo:(SecCSFlags)flags;\n\n@end\n\n#endif /* Binary_h */\n"
  },
  {
    "path": "LuLu/Extension/Binary.m",
    "content": "//\n//  File: Binary.m\n//  Project: Lulu\n//\n//  Created by: Patrick Wardle\n//  Copyright:  2017 Objective-See\n//\n\n#import \"Binary.h\"\n\n@implementation Binary\n\n@synthesize icon;\n@synthesize name;\n@synthesize path;\n@synthesize bundle;\n@synthesize metadata;\n@synthesize attributes;\n\n/* GLOBALS */\n\n//log handle\nextern os_log_t logHandle;\n\n//init binary object\n// note: CPU-intensive logic (code signing, etc) called manually\n-(id)init:(NSString*)binaryPath\n{\n    //init super\n    self = [super init];\n    if(nil != self)\n    {\n        //save path\n        self.path = binaryPath;\n        \n        //remove symlinks\n        self.path = [self.path stringByResolvingSymlinksInPath];\n        \n        //try load app bundle\n        // will be nil for non-apps\n        [self getBundle];\n        \n        //get name\n        [self getName];\n        \n        //get file attributes\n        [self getAttributes];\n        \n        //get meta data (spotlight)\n        [self getMetadata];\n    }\n\n    return self;\n}\n\n//try load app bundle\n// will be nil for non-apps\n-(void)getBundle\n{\n    //first try just with path\n    self.bundle = [NSBundle bundleWithPath:path];\n    \n    //that failed?\n    // try find it dynamically\n    if(nil == self.bundle)\n    {\n        //find bundle\n        self.bundle = findAppBundle(path);\n    }\n    \n    return;\n}\n\n//figure out binary's name\n// either via app bundle, or from path\n-(void)getName\n{\n    //first try get name from app bundle\n    // specifically, via grab name from 'CFBundleName'\n    if(nil != self.bundle)\n    {\n        //extract name\n        self.name = [self.bundle infoDictionary][@\"CFBundleName\"];\n    }\n    \n    //no app bundle || no 'CFBundleName'\n    // just use last component from path\n    if(nil == self.name)\n    {\n        //set name\n        self.name = [self.path lastPathComponent];\n    }\n    \n    return;\n}\n\n//get file attributes\n-(void)getAttributes\n{\n    //grab (file) attributes\n    self.attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:self.path error:nil];\n    \n    return;\n}\n\n//get (spotlight) meta data\n-(void)getMetadata\n{\n    //md item ref\n    MDItemRef mdItem = nil;\n    \n    //attributes names\n    CFArrayRef attributeNames = nil;\n\n    //create\n    mdItem = MDItemCreate(kCFAllocatorDefault, (CFStringRef)self.path);\n    if(nil == mdItem)\n    {\n        //bail\n        goto bail;\n    }\n    \n    //copy names\n    attributeNames = MDItemCopyAttributeNames(mdItem);\n    if(nil == attributeNames)\n    {\n        //bail\n        goto bail;\n    }\n    \n    //get metadata\n    self.metadata = CFBridgingRelease(MDItemCopyAttributes(mdItem, attributeNames));\n    \nbail:\n    \n    //release names\n    if(NULL != attributeNames)\n    {\n        //release\n        CFRelease(attributeNames);\n        attributeNames = NULL;\n    }\n    \n    //release md item\n    if(NULL != mdItem)\n    {\n        //release\n        CFRelease(mdItem);\n        mdItem = NULL;\n    }\n\n    return;\n}\n\n//get an icon for a process\n// for apps, this will be app's icon, otherwise just a standard system one\n-(void)getIcon\n{\n    //icon's file name\n    NSString* iconFile = nil;\n    \n    //icon's path\n    NSString* iconPath = nil;\n    \n    //icon's path extension\n    NSString* iconExtension = nil;\n    \n    //skip 'short' paths\n    // otherwise system logs an error\n    if( (YES != [self.path hasPrefix:@\"/\"]) &&\n        (nil == self.bundle) )\n    {\n        //bail\n        goto bail;\n    }\n    \n    //for app's\n    // extract their icon\n    if(nil != self.bundle)\n    {\n        //get file\n        iconFile = self.bundle.infoDictionary[@\"CFBundleIconFile\"];\n        \n        //get path extension\n        iconExtension = [iconFile pathExtension];\n        \n        //if its blank (i.e. not specified)\n        // go with 'icns'\n        if(YES == [iconExtension isEqualTo:@\"\"])\n        {\n            //set type\n            iconExtension = @\"icns\";\n        }\n        \n        //set full path\n        iconPath = [self.bundle pathForResource:[iconFile stringByDeletingPathExtension] ofType:iconExtension];\n        \n        //load it\n        self.icon = [[NSImage alloc] initWithContentsOfFile:iconPath];\n    }\n    \n    //process is not an app or couldn't get icon\n    // try to get it via shared workspace\n    if( (nil == self.bundle) ||\n        (nil == self.icon) )\n    {\n        //extract icon\n        self.icon = [[NSWorkspace sharedWorkspace] iconForFile:self.path];\n    }\n    \n    //make standard size...\n    [self.icon setSize:NSMakeSize(128, 128)];\n    \nbail:\n    \n    return;\n}\n\n//statically, generate signing info\n-(void)generateSigningInfo:(SecCSFlags)flags\n{\n    //signing info\n    NSMutableDictionary* extractedSigningInfo = nil;\n    \n    //extract signing info\n    extractedSigningInfo = extractSigningInfo(0, self.path, flags);\n    \n    //valid?\n    // save into iVar\n    if( (nil != extractedSigningInfo[KEY_CS_STATUS]) &&\n        (noErr == [extractedSigningInfo[KEY_CS_STATUS] intValue]))\n    {\n        //save\n        self.csInfo = extractedSigningInfo;\n    }\n    //dbg msg\n    else os_log_debug(logHandle, \"invalid code signing information for %{public}@: %{public}@\", self.path, extractedSigningInfo);\n    \n    return;\n}\n\n//for pretty printing\n-(NSString *)description\n{\n    //pretty print\n    return [NSString stringWithFormat: @\"name: %@\\npath: %@\\nattributes: %@\\nsigning info: %@\\nmetadata: %@\", self.name, self.path, self.attributes, self.metadata, self.csInfo];\n}\n\n@end\n"
  },
  {
    "path": "LuLu/Extension/BlockOrAllowList.h",
    "content": "//\n//  BlockOrAllowList.h\n//  Extension\n//\n//  Created by Patrick Wardle on 11/6/20.\n//  Copyright © 2020 Objective-See. All rights reserved.\n//\n\n@import Cocoa;\n@import OSLog;\n@import NetworkExtension;\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface BlockOrAllowList : NSObject\n\n/* PROPERTIES */\n\n//path\n@property(nonatomic, retain)NSString* path;\n\n//block list\n@property(nonatomic, retain)NSMutableSet* items;\n\n//modification time\n@property(nonatomic, retain)NSDate* lastModified;\n\n\n/* METHODS */\n\n//init\n// with a path\n-(id)init:(NSString*)path;\n\n//(re)load from disk\n-(void)load:(NSString*)path;\n\n//should reload\n// checks file modification time\n-(BOOL)shouldReload;\n\n//check if flow matches item on block list\n-(BOOL)isMatch:(NEFilterSocketFlow*)flow;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "LuLu/Extension/BlockOrAllowList.m",
    "content": "//\n//  BlockOrAllowList.m\n//  Extension\n//\n//  Created by Patrick Wardle on 11/6/20.\n//  Copyright © 2020 Objective-See. All rights reserved.\n//\n\n#import \"consts.h\"\n#import \"Preferences.h\"\n#import \"BlockOrAllowList.h\"\n\n/* GLOBALS */\n\n//log handle\nextern os_log_t logHandle;\n\n//preferences\nextern Preferences* preferences;\n\n@implementation BlockOrAllowList\n\n-(id)init:(NSString*)path\n{\n    //init super\n    self = [super init];\n    if(nil != self)\n    {\n        //save list\n        self.path = path;\n        \n        //load\n        [self load:self.path];\n    }\n    \n    return self;\n}\n\n//was specified block list remote\n// ...just checks if prefixed with http:// || https://\n-(BOOL)isRemote\n{\n    //specified path a URL?\n    return ((YES == [self.path hasPrefix:@\"http://\"]) || (YES == [self.path hasPrefix:@\"https://\"]));\n}\n\n//should reload\n// checks file modification time\n-(BOOL)shouldReload\n{\n    //flag\n    BOOL shouldReload = NO;\n    \n    //current mod. time\n    NSDate* modified = nil;\n    \n    //if it's remote\n    // can't tell, so default to no\n    if(YES == [self isRemote])\n    {\n        //bail\n        goto bail;\n    }\n    \n    //get modified timestamp\n    modified = [[NSFileManager.defaultManager attributesOfItemAtPath:self.path error:nil] objectForKey:NSFileModificationDate];\n\n    //was file modified?\n    if(NSOrderedDescending == [modified compare:self.lastModified])\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"block list was modified ...will reload\");\n        \n        //yes\n        shouldReload = YES;\n    }\n    \nbail:\n    \n    return shouldReload;\n}\n\n//(re)load\n-(void)load:(NSString*)path\n{\n    //error\n    NSError* error = nil;\n    \n    //file contents\n    NSString* list = nil;\n    \n    //sync\n    @synchronized (self) {\n        \n    //update path\n    self.path = path;\n        \n    //reset list\n    [self.items removeAllObjects];\n        \n    //dbg msg\n    os_log_debug(logHandle, \"%s\", __PRETTY_FUNCTION__);\n    \n    //check\n    // path?\n    if(0 == self.path.length)\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"no list specified...\");\n        \n        //bail\n        goto bail;\n    }\n        \n    //remote?\n    // load via URL\n    if(YES == [self isRemote])\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"(re)loading (remote) list\");\n        \n        //load\n        list = [NSString stringWithContentsOfURL:[NSURL URLWithString:self.path] encoding:NSUTF8StringEncoding error:&error];\n        if(nil != error)\n        {\n            //err msg\n            os_log_error(logHandle, \"ERROR: failed to (re)load (remote) list, %{public}@ (error: %{public}@)\", self.path, error);\n            \n            //bail\n            goto bail;\n        }\n        \n        //(re)load remote URL once a day\n        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(24 * 60 * 60 * NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{\n            \n            //dbg msg\n            os_log_debug(logHandle, \"(re)loading (remote) list\");\n            \n            //(re)load\n            [self load:self.path];\n            \n        });\n    }\n    \n    //local file\n    // check and load\n    else\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"(re)loading (local) list, %{public}@\", self.path);\n            \n        //(re)load\n        list = [NSString stringWithContentsOfFile:self.path encoding:NSUTF8StringEncoding error:&error];\n        if(nil != error)\n        {\n            //err msg\n            os_log_error(logHandle, \"ERROR: failed to (re)load (local) list, %{public}@ (error: %{public}@)\", self.path, error);\n            \n            //bail\n            goto bail;\n        }\n        \n        //save timestamp\n        self.lastModified = [[NSFileManager.defaultManager attributesOfItemAtPath:self.path error:nil] objectForKey:NSFileModificationDate];\n    }\n    \n    //init set\n    // of trimmed/lower-cased items\n    self.items = [NSMutableSet setWithArray:[[[list componentsSeparatedByString:@\"\\n\"] filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(NSString *item, NSDictionary *bindings) {\n                //trim\n                NSString* trimmed = [item stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];\n                \n                //make sure its not empty/not a comment\n                return (trimmed.length > 0 && ![trimmed hasPrefix:@\"#\"]);\n        \n            }]] valueForKey:@\"lowercaseString\"]];\n        \n    //dbg msg\n    os_log_debug(logHandle, \"(re)loaded %lu list items\", (unsigned long)self.items.count);\n    \n    } //sync\n\nbail:\n    \n    return;\n}\n\n//check if flow matches item on block or allow list\n// note: currently lists don't support port matching\n-(BOOL)isMatch:(NEFilterSocketFlow*)flow\n{\n    //match\n    BOOL isMatch = NO;\n    \n    //remote endpoint\n    NWHostEndpoint* remoteEndpoint = nil;\n    \n    //endpoint url/hosts\n    NSMutableSet* endpointNames = nil;\n    \n    //matches\n    NSSet* matches = nil;\n    \n    //extract remote endpoint\n    remoteEndpoint = (NWHostEndpoint*)flow.remoteEndpoint;\n    \n    //need to reload list?\n    // checks timestamp to see if modified\n    if(YES == [self shouldReload])\n    {\n        //(re)load list\n        [self load:self.path];\n    }\n    \n    //sync\n    @synchronized (self) {\n        \n    //init endpoint names\n    endpointNames = [NSMutableSet set];\n        \n    //add url\n    if(nil != flow.URL.absoluteString)\n    {\n        //add full url\n        [endpointNames addObject:flow.URL.absoluteString.lowercaseString];\n    }\n    \n    //add host\n    if(nil != flow.URL.host)\n    {\n        //add full url\n        [endpointNames addObject:flow.URL.host.lowercaseString];\n    }\n        \n    //add host name\n    if(nil != remoteEndpoint.hostname)\n    {\n        //add\n        [endpointNames addObject:remoteEndpoint.hostname.lowercaseString];\n    }\n    \n    //macOS 11+?\n    // add remote host name\n    if(@available(macOS 11, *))\n    {\n        //add remote host name\n        if(nil != flow.remoteHostname)\n        {\n            //add\n            [endpointNames addObject:flow.remoteHostname.lowercaseString];\n         \n            //if it starts w/ 'www.'\n            // strip and add that too\n            if(YES == [flow.remoteHostname hasPrefix:@\"www.\"])\n            {\n                //add\n                [endpointNames addObject:[[flow.remoteHostname substringFromIndex:4] lowercaseString]];\n            }\n        }\n    }\n    \n    //first check for \"all\"\n    // for IPV4 -> '0.0.0.0/0'\n    if( (AF_INET == flow.socketFamily) &&\n        ([self.items containsObject:@\"0.0.0.0/0\"]) )\n    {\n        isMatch = YES;\n        goto bail;\n    }\n    //for IPV6 -> '::/0'\n    else if( (AF_INET6 == flow.socketFamily) &&\n             ([self.items containsObject:@\"::/0\"]) )\n    {\n        isMatch = YES;\n        goto bail;\n    }\n   \n    //find matches\n    matches = [self.items objectsPassingTest:^BOOL(NSString* item, BOOL* stop) {\n        return [endpointNames containsObject:item];\n    }];\n        \n    //any matches?\n    if(0 != matches.count)\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"endpoint names %{public}@ matched the following list items %{public}@\", endpointNames, matches);\n       \n        //set flag\n        isMatch = YES;\n    }\n        \n    }//sync\n    \nbail:\n    \n    return isMatch;\n}\n\n@end\n"
  },
  {
    "path": "LuLu/Extension/Extension.entitlements",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>com.apple.developer.networking.networkextension</key>\n\t<array>\n\t\t<string>content-filter-provider-systemextension</string>\n\t</array>\n\t<key>com.apple.security.application-groups</key>\n\t<array>\n\t\t<string>$(TeamIdentifierPrefix)com.objective-see.lulu</string>\n\t</array>\n\t<key>com.apple.security.temporary-exception.files.absolute-path.read-write</key>\n\t<array>\n\t\t<string>/private/var/db/mds/</string>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "LuLu/Extension/FilterDataProvider.h",
    "content": "//\n//  FilterDataProvider.h\n//  LuLu\n//\n//  Created by Patrick Wardle on 8/1/20.\n//  Copyright (c) 2020 Objective-See. All rights reserved.\n//\n\n#import <bsm/libbsm.h>\n\n@import OSLog;\n@import NetworkExtension;\n\n#import \"GrayList.h\"\n\n@interface FilterDataProvider : NEFilterDataProvider\n\n/* PROPERTIES */\n\n//(process) cache\n@property(atomic, retain)NSCache* cache;\n\n//graylist obj\n@property(nonatomic, retain)GrayList* grayList;\n\n//related flows\n@property(nonatomic, retain)NSMutableDictionary* relatedFlows;\n\n/* METHODS */\n\n//get best hostname from flow\n// prioritizes domain names over IP addresses\n-(NSString*)getBestHostnameFromFlow:(NEFilterSocketFlow*)flow;\n\n@end\n"
  },
  {
    "path": "LuLu/Extension/FilterDataProvider.m",
    "content": "//\n//  FilterDataProvider.m\n//  LuLu\n//\n//  Created by Patrick Wardle on 8/1/20.\n//  Copyright (c) 2020 Objective-See. All rights reserved.\n//\n\n#import \"Rule.h\"\n#import \"Rules.h\"\n#import \"Alerts.h\"\n#import \"consts.h\"\n#import \"GrayList.h\"\n#import \"BlockOrAllowList.h\"\n#import \"utilities.h\"\n#import \"Preferences.h\"\n#import \"XPCUserProto.h\"\n#import \"FilterDataProvider.h\"\n\n//verdicts\ntypedef NS_ENUM(NSInteger, FlowVerdict) {\n    kFlowVerdictAllow,\n    kFlowVerdictBlock,\n    kFlowVerdictPause,      // new alert shown, waiting for user\n    kFlowVerdictRelated,    // another alert already shown for this process\n};\n\n/* GLOBALS */\n\n//alerts\nextern Alerts* alerts;\n\n//log handle\nextern os_log_t logHandle;\n\n//rules\nextern Rules* rules;\n\n//preferences\nextern Preferences* preferences;\n\n//allow list\nextern BlockOrAllowList* allowList;\n\n//block list\nextern BlockOrAllowList* blockList;\n\n@implementation FilterDataProvider\n\n@synthesize cache;\n@synthesize grayList;\n\n//init\n-(id)init\n{\n    //super\n    self = [super init];\n    if(nil != self)\n    {\n        //init cache\n        cache = [[NSCache alloc] init];\n        \n        //set cache limit\n        self.cache.countLimit = 2048;\n        \n        //init gray list\n        grayList = [[GrayList alloc] init];\n        \n        //alloc related flows\n        self.relatedFlows = [NSMutableDictionary dictionary];\n        \n    }\n    \n    return self;\n}\n\n//start filter\n-(void)startFilterWithCompletionHandler:(void (^)(NSError *error))completionHandler {\n    \n    //rules\n    NSMutableArray<NEFilterRule*>* rules = nil;\n\n    //network rules\n    NENetworkRule* anyOutboundRule = nil;\n    NENetworkRule* loopbackRule4 = nil;\n    NENetworkRule* loopbackRule6 = nil;\n\n    //filter settings\n    NEFilterSettings* filterSettings = nil;\n\n    //log msg\n    os_log_debug(logHandle, \"%s\", __PRETTY_FUNCTION__);\n\n    //init rules array\n    rules = [NSMutableArray array];\n\n    //Rule 1:\n    // IPv4 loopback (127.0.0.0/8), any port\n    NWHostEndpoint* loopback4 = [NWHostEndpoint endpointWithHostname:@\"127.0.0.0\" port:@\"0\"];\n    loopbackRule4 = [[NENetworkRule alloc] initWithRemoteNetwork:loopback4\n                                                   remotePrefix:8\n                                                    localNetwork:nil\n                                                     localPrefix:0\n                                                        protocol:NENetworkRuleProtocolAny\n                                                       direction:NETrafficDirectionOutbound];\n    [rules addObject:[[NEFilterRule alloc] initWithNetworkRule:loopbackRule4 action:NEFilterActionFilterData]];\n\n    //Rule 2:\n    // IPv6 loopback (::1/128), any port\n    NWHostEndpoint* loopback6 = [NWHostEndpoint endpointWithHostname:@\"::1\" port:@\"0\"];\n    loopbackRule6 = [[NENetworkRule alloc] initWithRemoteNetwork:loopback6\n                                                   remotePrefix:128\n                                                    localNetwork:nil\n                                                     localPrefix:0\n                                                        protocol:NENetworkRuleProtocolAny\n                                                       direction:NETrafficDirectionOutbound];\n    [rules addObject:[[NEFilterRule alloc] initWithNetworkRule:loopbackRule6 action:NEFilterActionFilterData]];\n\n    //Rule 3:\n    // any/all outbound traffic (non-loopback)\n    anyOutboundRule = [[NENetworkRule alloc] initWithRemoteNetwork:nil\n                                                     remotePrefix:0\n                                                      localNetwork:nil\n                                                       localPrefix:0\n                                                          protocol:NENetworkRuleProtocolAny\n                                                         direction:NETrafficDirectionOutbound];\n    [rules addObject:[[NEFilterRule alloc] initWithNetworkRule:anyOutboundRule action:NEFilterActionFilterData]];\n\n    //init filter settings\n    filterSettings = [[NEFilterSettings alloc] initWithRules:rules defaultAction:NEFilterActionAllow];\n\n    //apply rules\n    [self applySettings:filterSettings completionHandler:^(NSError * _Nullable error) {\n\n        //log msg\n        os_log_debug(logHandle, \"'applySettings' completed\");\n\n        //error?\n        if(nil != error) os_log_error(logHandle, \"ERROR: failed to apply filter settings: %@\", error.localizedDescription);\n\n        //call completion handler\n        completionHandler(error);\n    }];\n\n    return;\n}\n\n//stop filter\n-(void)stopFilterWithReason:(NEProviderStopReason)reason completionHandler:(void (^)(void))completionHandler {\n    \n    //log msg\n    os_log_debug(logHandle, \"method '%s' invoked with %ld\", __PRETTY_FUNCTION__, (long)reason);\n    \n    //extra dbg info\n    if(NEProviderStopReasonUserInitiated == reason)\n    {\n        //log msg\n        os_log_debug(logHandle, \"reason: NEProviderStopReasonUserInitiated\");\n    }\n    \n    //required\n    completionHandler();\n    \n    return;\n}\n\n//handle flow\n-(NEFilterNewFlowVerdict *)handleNewFlow:(NEFilterFlow *)flow {\n    \n    //socket flow\n    NEFilterSocketFlow* socketFlow = nil;\n    \n    //remote endpoint\n    NWHostEndpoint* remoteEndpoint = nil;\n    \n    //verdict\n    NEFilterNewFlowVerdict* verdict = nil;\n    \n    //log msg\n    os_log_debug(logHandle, \"method '%s' invoked\", __PRETTY_FUNCTION__);\n    \n    //init verdict to allow\n    verdict = [NEFilterNewFlowVerdict allowVerdict];\n    \n    //no prefs (yet) or disabled\n    // just allow the flow (don't block)\n    if( (0 == preferences.preferences.count) ||\n        (YES == [preferences.preferences[PREF_IS_DISABLED] boolValue]) )\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"no prefs (yet) || disabled, so allowing flow\");\n        \n        //bail\n        goto bail;\n    }\n    \n    //typecast\n    socketFlow = (NEFilterSocketFlow*)flow;\n    \n    //log msg\n    //os_log_debug(logHandle, \"flow: %{public}@\", flow);\n    \n    //extract remote endpoint\n    remoteEndpoint = (NWHostEndpoint*)socketFlow.remoteEndpoint;\n    \n    //log msg\n    os_log_debug(logHandle, \"remote endpoint: %{public}@ / url: %{public}@\", remoteEndpoint, flow.URL);\n    \n    //ignore non-outbound traffic\n    // even though we init'd `NETrafficDirectionOutbound`, sometimes get inbound traffic :|\n    if(NETrafficDirectionOutbound != socketFlow.direction)\n    {\n        //log msg\n        os_log_debug(logHandle, \"ignoring non-outbound traffic (direction: %ld)\", (long)socketFlow.direction);\n           \n        //bail\n        goto bail;\n    }\n    \n    //process flow\n    // determine verdict/deliver alert\n    switch([self processEvent:flow]) {\n            \n        //allow\n        case kFlowVerdictAllow:\n            os_log_debug(logHandle, \"verdict: allow\");\n            verdict = [NEFilterNewFlowVerdict allowVerdict];\n            break;\n        \n        //block\n        case kFlowVerdictBlock:\n            os_log_debug(logHandle, \"verdict: block\");\n            verdict = [NEFilterNewFlowVerdict dropVerdict];\n            break;\n            \n        //pause\n        case kFlowVerdictPause:\n            os_log_debug(logHandle, \"verdict: pause\");\n            verdict = [NEFilterNewFlowVerdict pauseVerdict];\n            break;\n            \n        //related\n        // pause & save\n        case kFlowVerdictRelated:\n        {\n            os_log_debug(logHandle, \"verdict: related\");\n            \n            verdict = [NEFilterNewFlowVerdict pauseVerdict];\n            \n            //save as related flow\n            Process* process = [self.cache objectForKey:flow.sourceAppAuditToken];\n            if(process) {\n                [self addRelatedFlow:process.key flow:socketFlow];\n            }\n            //no process\n            // just allow\n            else {\n                verdict = [NEFilterNewFlowVerdict allowVerdict];\n            }\n            \n            break;\n        }\n    }\n    \n    //log msg\n    os_log_debug(logHandle, \"verdict: %{public}@\", verdict);\n    \nbail:\n        \n    return verdict;\n}\n\n//process a network out event from the network extension (OS)\n// if there is no matching rule, will tell client to show alert\n-(FlowVerdict)processEvent:(NEFilterFlow*)flow {\n    \n    //process obj\n    Process* process = nil;\n    \n    //flag\n    BOOL csChange = NO;\n    \n    //matching rule obj\n    Rule* matchingRule = nil;\n    \n    //console user\n    NSString* consoleUser = nil;\n    \n    //rule info\n    NSMutableDictionary* info = nil;\n    \n    //default to allow (on errors, etc)\n    FlowVerdict verdict = kFlowVerdictAllow;\n    \n    //(ext) install date\n    static NSDate* installDate = nil;\n    \n    //token\n    static dispatch_once_t onceToken = 0;\n    \n    //grab console user\n    consoleUser = getConsoleUser();\n    \n    //check cache for process\n    process = [self.cache objectForKey:flow.sourceAppAuditToken];\n    if(!process) {\n        \n        os_log_debug(logHandle, \"no process found in cache, will create\");\n        \n        //create\n        // also adds to cache\n        process = [self createProcess:flow];\n    }\n\n    //in cache\n    else\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"found process object in cache: %{public}@ (pid: %d)\", process.path, process.pid);\n    }\n    \n    //sanity check\n    // process exited? deny\n    pid_t pid = audit_token_to_pid(*(audit_token_t*)flow.sourceAppAuditToken.bytes);\n    if(!isAlive(pid))\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"process %d has exited, DENYING flow\", pid);\n        \n        //block\n        verdict = kFlowVerdictBlock;\n        goto bail;\n    }\n    \n    //sanity check\n    // no process? just allow...\n    if(nil == process)\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: failed to create process for flow, will allow\");\n        \n        //bail\n        goto bail;\n    }\n        \n    //CHECK:\n    // different logged in user?\n    // just allow flow, as we don't want to block their traffic\n    if( (nil != consoleUser) && (nil != alerts.consoleUser) &&\n        (YES != [alerts.consoleUser isEqualToString:consoleUser]) )\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"current console user '%{public}@', is different than '%{public}@', so allowing flow: %{public}@\", consoleUser, alerts.consoleUser, ((NEFilterSocketFlow*)flow).remoteEndpoint);\n        \n        //all set\n        goto bail;\n    }\n    \n    //CHECK:\n    // client in (full) block mode? ...block!\n    // unless there is an allow list set, which we'll check\n    if(YES == [preferences.preferences[PREF_BLOCK_MODE] boolValue])\n    {\n        //but allow list set?\n        if( (YES == [preferences.preferences[PREF_USE_ALLOW_LIST] boolValue]) &&\n            (YES == [allowList isMatch:(NEFilterSocketFlow*)flow]) )\n        {\n            //dbg msg\n            os_log_debug(logHandle, \"client in block mode, but flow matches item in allow list, so allowing\");\n                \n            //allow\n            verdict = kFlowVerdictAllow;\n                \n            //all set\n            goto bail;\n        }\n        \n        //dbg msg\n        os_log_debug(logHandle, \"client in block mode (and item not on allow list), so disallowing %d/%{public}@\", process.pid, process.binary.name);\n        \n        //deny\n        verdict = kFlowVerdictBlock;\n        \n        //all set\n        goto bail;\n    }\n        \n    //CHECK:\n    // client using (global) block list\n    if( (YES == [preferences.preferences[PREF_USE_BLOCK_LIST] boolValue]) &&\n        (0 != [preferences.preferences[PREF_BLOCK_LIST] length]) )\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"client is using block list '%{public}@' (%lu items) ...will check for match\", preferences.preferences[PREF_BLOCK_LIST], (unsigned long)blockList.items.count);\n        \n        //match in block list?\n        if(YES == [blockList isMatch:(NEFilterSocketFlow*)flow])\n        {\n            //dbg msg\n            os_log_debug(logHandle, \"flow matches item in block list, so denying\");\n            \n            //deny\n            verdict = kFlowVerdictBlock;\n            \n            //all set\n            goto bail;\n        }\n        //dbg msg\n        else os_log_debug(logHandle, \"remote endpoint/URL not on block list...\");\n    }\n    \n    //CHECK:\n    // client using (global) allow list\n    if( (YES == [preferences.preferences[PREF_USE_ALLOW_LIST] boolValue]) &&\n        (0 != [preferences.preferences[PREF_ALLOW_LIST] length]) )\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"client is using allow list '%{public}@' (%lu items) ...will check for match\", preferences.preferences[PREF_ALLOW_LIST], (unsigned long)allowList.items.count);\n        \n        //match in allow list?\n        if(YES == [allowList isMatch:(NEFilterSocketFlow*)flow])\n        {\n            //dbg msg\n            os_log_debug(logHandle, \"flow matches item in allow list, so allowing\");\n            \n            //allow\n            verdict = kFlowVerdictAllow;\n            \n            //all set\n            goto bail;\n        }\n        \n        //dbg msg\n        else os_log_debug(logHandle, \"remote endpoint/URL not on allow list...\");\n    }\n    \n    //CHECK:\n    // allow localhost enabled?\n    if([preferences.preferences[PREF_ALLOW_LOCALHOST] boolValue])\n    {\n        NEFilterSocketFlow* socketFlow = (NEFilterSocketFlow*)flow;\n        NWHostEndpoint* remoteEndpoint = (NWHostEndpoint*)socketFlow.remoteEndpoint;\n        \n        //localhost?\n        if([self isLocalhostHostname:remoteEndpoint.hostname]) {\n            \n            os_log_debug(logHandle, \"localhost allowed (preferences), so allowing loopback to %{public}@\", remoteEndpoint);\n            \n            //allow\n            verdict = kFlowVerdictAllow;\n            \n            //all set\n            goto bail;\n        }\n    }\n    \n    //CHECK:\n    // check for existing rule\n    \n    //existing rule for process?\n    matchingRule = [rules find:process flow:(NEFilterSocketFlow*)flow csChange:&csChange];\n    if(nil != matchingRule)\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"found matching rule for %d/%{public}@: %{public}@\", process.pid, process.binary.name, matchingRule);\n        \n        //matching rule !global/!directory?\n        // add its 'external' path (as might be different than original)\n        if( (YES != matchingRule.isGlobal.boolValue) &&\n            (YES != matchingRule.isDirectory.boolValue) )\n        {\n            //add path\n            if(nil != process.path)\n            {\n                //add\n                [rules.rules[process.key][KEY_PATHS] addObject:process.path];\n            }\n        }\n        \n        //deny?\n        // otherwise will default to allow\n        if(RULE_STATE_BLOCK == matchingRule.action.intValue)\n        {\n            //dbg msg\n            os_log_debug(logHandle, \"setting verdict to: BLOCK\");\n            \n            //deny\n            verdict = kFlowVerdictBlock;\n        }\n        //allow (msg)\n        else os_log_debug(logHandle, \"rule says: ALLOW\");\n    \n        //all set\n        goto bail;\n    }\n\n    /* NO MATCHING RULE FOUND */\n    \n    //cs change?\n    // update item's rules with new code signing info\n    // note: user will be informed about this, if/when alert is delivered\n    if(YES == csChange)\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"found rule set for %d/%{public}@: %{public}@, but code signing info has changed\", process.pid, process.binary.name, matchingRule);\n        \n        //update cs info\n        [rules updateCSInfo:process];\n    }\n    //no matching rule found?\n    else\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"no (saved) rule found for %d/%{public}@\", process.pid, process.binary.name);\n    }\n\n    //CHECK:\n    // client in passive mode?\n    // take action based on user's settting ...allow/block\n    if(YES == [preferences.preferences[PREF_PASSIVE_MODE] boolValue])\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"client in passive mode...\");\n        \n        //user action: allow?\n        if(PREF_PASSIVE_MODE_ALLOW == [preferences.preferences[PREF_PASSIVE_MODE_ACTION] integerValue])\n        {\n            //dbg msg\n            os_log_debug(logHandle, \"passive mode: action is 'allow', so allowing %d/%{public}@\", process.pid, process.binary.name);\n            \n            //allow\n            verdict = kFlowVerdictAllow;\n        }\n        \n        //user action: block?\n        else\n        {\n            //dbg msg\n            os_log_debug(logHandle, \"passive mode: action is 'block', so blocking %d/%{public}@\", process.pid, process.binary.name);\n            \n            //block\n            verdict = kFlowVerdictBlock;\n        }\n        \n        //create rule?\n        if(PREF_PASSIVE_MODE_RULES_YES == [preferences.preferences[PREF_PASSIVE_MODE_RULES] integerValue])\n        {\n            //dbg msg\n            os_log_debug(logHandle, \"passive mode: create rules is set, so creating rule for new connection\");\n            \n            //extract remote endpoint information\n            NWHostEndpoint* remoteEndpoint = (NWHostEndpoint*)((NEFilterSocketFlow*)flow).remoteEndpoint;\n            \n            //init info for rule creation with specific endpoint information\n            info = [@{KEY_PATH:process.path, KEY_TYPE:@RULE_TYPE_PASSIVE} mutableCopy];\n            \n            //get best hostname (prioritizes domain names over IP addresses)\n            NSString* bestHostname = [self getBestHostnameFromFlow:(NEFilterSocketFlow*)flow];\n            \n            //add endpoint address (hostname) if available\n            if(0!= bestHostname.length) {\n                info[KEY_ENDPOINT_ADDR] = bestHostname;\n            } else {\n                info[KEY_ENDPOINT_ADDR] = VALUE_ANY;\n            }\n            \n            //add endpoint port if available\n            if(0 != remoteEndpoint.port.length) {\n                info[KEY_ENDPOINT_PORT] = remoteEndpoint.port;\n            } else {\n                info[KEY_ENDPOINT_PORT] = VALUE_ANY;\n            }\n            \n            //add protocol if available\n            if(((NEFilterSocketFlow*)flow).socketProtocol > 0)\n            {\n                info[KEY_PROTOCOL] = [NSNumber numberWithInt:((NEFilterSocketFlow*)flow).socketProtocol];\n            }\n\n            //add process cs info?\n            if(nil != process.csInfo) info[KEY_CS_INFO] = process.csInfo;\n            \n            //add action: allow\n            if(PREF_PASSIVE_MODE_ALLOW == [preferences.preferences[PREF_PASSIVE_MODE_ACTION] integerValue])\n            {\n                //dbg msg\n                os_log_debug(logHandle, \"passive mode: creating rule with 'allow'\");\n                \n                //allow\n                info[KEY_ACTION] = @RULE_STATE_ALLOW;\n            }\n            //add action: block\n            else\n            {\n                //dbg msg\n                os_log_debug(logHandle, \"passive mode: creating rule with 'block'\");\n                \n                //block\n                info[KEY_ACTION] = @RULE_STATE_BLOCK;\n            }\n            \n            //create and add rule\n            if(YES != [rules add:[[Rule alloc] init:info] save:YES])\n            {\n                //err msg\n                os_log_error(logHandle, \"ERROR: failed to add (passive) rule for %{public}@\", info[KEY_PATH]);\n                 \n                //bail\n                goto bail;\n            }\n            \n            //tell user rules changed\n            [alerts.xpcUserClient rulesChanged];\n        }\n        //no rule creation needed\n        else\n        {\n            //dbg msg\n            os_log_debug(logHandle, \"passive mode: create rules is not set...\");\n        }\n        \n        //all set\n        goto bail;\n    }\n    \n    //dbg msg\n    os_log_debug(logHandle, \"client not in passive mode...\");\n    \n    //CHECK:\n    // there is related alert shown (i.e. for same process)\n    // save this flow, as only want to process once user responds to first alert\n    if(YES == [alerts isRelated:process])\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"an alert is shown for process %d/%{public}@, so holding off delivering for now...\", process.pid, process.binary.name);\n        \n        //related\n        // will pause\n        verdict = kFlowVerdictRelated;\n        \n        //bail\n        goto bail;\n    }\n    \n    //dbg msg\n    os_log_debug(logHandle, \"no related alert, currently shown...\");\n    \n    //CHECK:\n    // Apple process and 'PREF_ALLOW_APPLE' is set? Allow\n    // Unless:\n    //  a) Its on the 'graylist' (e.g. curl) as these can be (ab)used by malware\n    //  b) There are other rules for this same process (even though they didn't match)\n    if(YES == [preferences.preferences[PREF_ALLOW_APPLE] boolValue])\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"'Allow Apple' preference is set, will check if is an Apple binary\");\n        \n        //signed by Apple?\n        if(Apple == [process.csInfo[KEY_CS_SIGNER] intValue])\n        {\n            //dbg msg\n            os_log_debug(logHandle, \"is an Apple binary...\");\n            \n            //graylisted item?\n            // pause and alert user\n            if(YES == [self.grayList isGrayListed:process])\n            {\n                //dbg msg\n                os_log_debug(logHandle, \"while signed by apple, %d/%{public}@ is gray listed, so will alert\", process.pid, process.binary.name);\n                \n                //pause\n                verdict = kFlowVerdictPause;\n                \n                //create/deliver alert\n                [self alert:(NEFilterSocketFlow*)flow process:process csChange:csChange];\n            }\n            //other rules for this process?\n            else if(0 != [rules.rules[process.key][KEY_RULES] count])\n            {\n                //dbg msg\n                os_log_debug(logHandle, \"while signed by apple, %d/%{public}@ has other (non-matching) rules, so will alert\", process.pid, process.binary.name);\n                \n                //pause\n                verdict = kFlowVerdictPause;\n                \n                //create/deliver alert\n                [self alert:(NEFilterSocketFlow*)flow process:process csChange:csChange];\n            }\n            //otherwise its a apple binary\n            // not on graylist and w/ no other rules, so allow\n            else\n            {\n                //dbg msg\n                os_log_debug(logHandle, \"due to preferences, allowing (non-graylisted) apple process %d/%{public}@\", process.pid, process.path);\n                \n                //init for (rule) info\n                // type: apple, action: allow\n                info = [@{KEY_PATH:process.path, KEY_ACTION:@RULE_STATE_ALLOW, KEY_TYPE:@RULE_TYPE_APPLE} mutableCopy];\n                \n                //add process cs info\n                if(nil != process.csInfo)\n                {\n                    //add\n                    info[KEY_CS_INFO] = process.csInfo;\n                }\n                \n                //add key\n                info[KEY_KEY] = process.key;\n                \n                //add/save\n                if(YES != [rules add:[[Rule alloc] init:info] save:YES])\n                {\n                    //err msg\n                    os_log_error(logHandle, \"ERROR: failed to add rule\");\n                    \n                    //bail\n                    goto bail;\n                }\n                \n                //tell user rules changed\n                [alerts.xpcUserClient rulesChanged];\n            }\n            \n            //all set\n            goto bail;\n            \n        } //signed by apple\n    }\n    //dbg msg\n    else\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"'Allow Apple' preference not set, so skipped 'Is Apple' check\");\n    }\n    \n    //'allow installed' check\n    // if preference is enabled, item is 3rd-party, internal, and hasn't had its CS changed ...allow!\n    if( (YES == [preferences.preferences[PREF_ALLOW_INSTALLED] boolValue]) &&\n        (Apple != [process.csInfo[KEY_CS_SIGNER] intValue]) &&\n        (YES != csChange) )\n    {\n        //only check internal processes\n        // so, like ignore ones from DMGs, external drives, etc.\n        if(YES == isInternalProcess(process.path))\n        {\n            //app date\n            NSDate* date = nil;\n            \n            //dbg msg\n            os_log_debug(logHandle, \"3rd-party (internal) app, plus 'PREF_ALLOW_INSTALLED' is set...\");\n            \n            //only once\n            // get install date\n            dispatch_once(&onceToken, ^{\n                \n                //get LuLu's install date\n                installDate = preferences.preferences[PREF_INSTALL_TIMESTAMP];\n                \n                //dbg msg\n                os_log_debug(logHandle, \"LuLu's install date: %{public}@\", installDate);\n                \n            });\n            \n            //get item's date added\n            date = dateAdded(process.path);\n            if( (nil != date) &&\n                (NSOrderedAscending == [date compare:installDate]) )\n            {\n                //dbg msg\n                os_log_debug(logHandle, \"3rd-party item was installed prior (%@) to LuLu (%@), allowing & adding rule\", date, installDate);\n                \n                //init info for rule creation\n                info = [@{KEY_PATH:process.path, KEY_ACTION:@RULE_STATE_ALLOW, KEY_TYPE:@RULE_TYPE_BASELINE} mutableCopy];\n                \n                //add process cs info\n                if(nil != process.csInfo)\n                {\n                    info[KEY_CS_INFO] = process.csInfo;\n                }\n                \n                //create and add rule\n                if(YES != [rules add:[[Rule alloc] init:info] save:YES])\n                {\n                    //err msg\n                    os_log_error(logHandle, \"ERROR: failed to add rule for %{public}@\", info[KEY_PATH]);\n                     \n                    //bail\n                    goto bail;\n                }\n                \n                //tell user rules changed\n                [alerts.xpcUserClient rulesChanged];\n                \n                //all set\n                goto bail;\n            }\n            //newer\n            else\n            {\n                //dbg msg\n                os_log_debug(logHandle, \"3rd-party item date (%@), is after LuLu's install date (%@)\", date, installDate);\n            }\n        }\n        //item is external\n        else\n        {\n            os_log_debug(logHandle, \"%{public}@ is external, so skipping 'allow installed' check\", process.path);\n        }\n    }\n    \n    //allow dns traffic pref set?\n    // really, just any UDP traffic over port 53\n    if(YES == [preferences.preferences[PREF_ALLOW_DNS] boolValue])\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"'allow DNS traffic' is enabled, so checking port/protocol\");\n        \n        //check proto (UDP) and port (53)\n        if( (IPPROTO_UDP == ((NEFilterSocketFlow*)flow).socketProtocol) &&\n            (YES == [((NWHostEndpoint*)((NEFilterSocketFlow*)flow).remoteEndpoint).port isEqualToString:@\"53\"]) )\n        {\n            //dbg msg\n            os_log_debug(logHandle, \"protocol is 'UDP' and port is '53', (so likely DNS traffic) ...will allow\" );\n            \n            //allow\n            verdict = kFlowVerdictAllow;\n            \n            //done\n            goto bail;\n        }\n    }\n    \n    //allow simulator apps?\n    if(YES == [preferences.preferences[PREF_ALLOW_SIMULATOR] boolValue])\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"'allow simulator apps' is enabled, so checking process\");\n        \n        //is simulator app?\n        if(YES == isSimulatorApp(process.path))\n        {\n            //dbg msg\n            os_log_debug(logHandle, \"%{public}@, is an simulator app, so will allow\", process.path);\n            \n            //allow\n            verdict = kFlowVerdictAllow;\n            \n            //done\n            goto bail;\n        }\n    }\n    \n    //no user?\n    // allow, but create rule for user to review\n    if( (nil == consoleUser) ||\n        (nil == alerts.xpcUserClient) )\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"no active user or no connected client, will allow (and create rule)...\");\n        \n        //init info for rule creation\n        info = [@{KEY_PATH:process.path, KEY_ACTION:@RULE_STATE_ALLOW, KEY_TYPE:@RULE_TYPE_PASSIVE} mutableCopy];\n\n        //add process cs info?\n        if(nil != process.csInfo) info[KEY_CS_INFO] = process.csInfo;\n        \n        //create and add rule\n        if(YES != [rules add:[[Rule alloc] init:info] save:YES])\n        {\n            //err msg\n            os_log_error(logHandle, \"ERROR: failed to add rule for %{public}@\", info[KEY_PATH]);\n             \n            //bail\n            goto bail;\n        }\n        \n        //tell user rules changed\n        [alerts.xpcUserClient rulesChanged];\n        \n        //all set\n        goto bail;\n    }\n    \n    //sending to user, so pause!\n    verdict = kFlowVerdictPause;\n        \n    //create/deliver alert\n    // note: handles response + next/any related flow\n    [self alert:(NEFilterSocketFlow*)flow process:process csChange:csChange];\n    \nbail:\n    \n    //log msg\n    // match on this if you want detailed insight into LuLu's decision\n    // log stream --level debug --predicate 'subsystem == \"com.objective-see.lulu\" && composedMessage BEGINSWITH \"[LULU]\"'\n    os_log_debug(logHandle, \"[LULU] PROCESS: %{public}@, FLOW (endpoint): %{public}@, RULE: %{public}@, verdict: %ld\", process.path, ((NEFilterSocketFlow*)flow).remoteEndpoint, matchingRule, verdict);\n    \n    return verdict;\n}\n\n//1. Create and deliver alert\n//2. Handle response (and process other shown alerts, etc.)\n-(void)alert:(NEFilterSocketFlow*)flow process:(Process*)process csChange:(BOOL)csChange\n{\n    //alert\n    NSMutableDictionary* alert = nil;\n    \n    //rule\n    __block Rule* rule = nil;\n    \n    //create alert\n    alert = [alerts create:(NEFilterSocketFlow*)flow process:process];\n    \n    //add cs change\n    alert[KEY_CS_CHANGE] = [NSNumber numberWithBool:csChange];\n    \n    //dbg msg\n    os_log_debug(logHandle, \"created alert...\");\n\n    //deliver alert\n    // and process user response\n    if(YES != [alerts deliver:alert reply:^(NSDictionary* alert)\n    {\n        //verdict\n        NEFilterNewFlowVerdict* verdict = nil;\n        \n        //log msg\n        // note, this msg persists in log\n        os_log(logHandle, \"(user) response: \\\"%@\\\" for %{public}@, that was trying to connect to %{public}@:%{public}@\", (RULE_STATE_BLOCK == [alert[KEY_ACTION] unsignedIntValue]) ? @\"block\" : @\"allow\", alert[KEY_PATH], alert[KEY_ENDPOINT_ADDR], alert[KEY_ENDPOINT_PORT]);\n        \n        //init verdict to allow\n        verdict = [NEFilterNewFlowVerdict allowVerdict];\n        \n        //user replied with block?\n        if( (nil != alert[KEY_ACTION]) &&\n            (RULE_STATE_BLOCK == [alert[KEY_ACTION] unsignedIntValue]) )\n        {\n            //verdict: block\n            verdict = [NEFilterNewFlowVerdict dropVerdict];\n        }\n        \n        //resume flow w/ verdict\n        [self resumeFlow:flow withVerdict:verdict];\n        \n        //init rule\n        rule = [[Rule alloc] init:alert];\n\n        //add / save\n        [rules add:rule save:![rule isTemporary]];\n\n        //remove from 'shown'\n        [alerts removeShown:alert];\n        \n        //tell user rules changed\n        [alerts.xpcUserClient rulesChanged];\n        \n        //process (any) related flows\n        // now that rule is created, related flows should match it or generate new alerts\n        [self processRelatedFlow:alert[KEY_KEY]];\n    }])\n    {\n        //failed to deliver, so allow\n        [self resumeFlow:flow withVerdict:[NEFilterNewFlowVerdict allowVerdict]];\n        \n        //process related flows\n        [self processRelatedFlow:alert[KEY_KEY]];\n    }\n    \n    //delivered to user\n    else\n    {\n        //save as shown\n        // needed so related (same process!) alerts aren't delivered as well\n        [alerts addShown:alert];\n    }\n    \n    return;\n}\n\n\n//add an alert to 'related'\n// invoked when there is already an alert shown for process\n// once user responds to alert, these will then be processed\n-(void)addRelatedFlow:(NSString*)key flow:(NEFilterSocketFlow*)flow\n{\n    //dbg msg\n    os_log_debug(logHandle, \"adding flow to 'related': %{public}@ / %{public}@\", key, flow);\n    \n    if(!key) {\n        return;\n    }\n    \n    //sync/save\n    @synchronized(self.relatedFlows)\n    {\n        //first time\n        // init array for item (process) alerts\n        if(!self.relatedFlows[key]) {\n            self.relatedFlows[key] = [NSMutableArray array];\n        }\n        \n        //only add if new\n        if(![self.relatedFlows[key] containsObject:flow]) {\n            [self.relatedFlows[key] addObject:flow];\n        }\n    }\n\n    return;\n}\n\n//process any related flows\n-(void)processRelatedFlow:(NSString*)key\n{\n    //dbg msg\n    os_log_debug(logHandle, \"processing %lu related flow(s) for %{public}@\", (unsigned long)[self.relatedFlows[key] count], key);\n\n    while(YES)\n    {\n        NEFilterSocketFlow* flow = nil;\n\n        //dequeue one flow\n        @synchronized(self.relatedFlows) {\n            \n            NSMutableArray* queue = self.relatedFlows[key];\n            \n            //done?\n            if(!queue.count) {\n                os_log_debug(logHandle, \"drained (processed) all related flows\");\n                [self.relatedFlows removeObjectForKey:key];\n                break;\n            }\n            \n            flow = queue.firstObject;\n            [queue removeObjectAtIndex:0];\n        }\n\n        //process\n        FlowVerdict flowVerdict = [self processEvent:flow];\n\n        //(still) related?\n        // (re)add and be done for now\n        if(flowVerdict == kFlowVerdictRelated) {\n            os_log_debug(logHandle, \"flow is (still) related\");\n            [self addRelatedFlow:key flow:flow];\n            break;\n        }\n        \n        //paused (asked user)\n        // asked user, so be done for now too\n        else if(flowVerdict == kFlowVerdictPause) {\n            os_log_debug(logHandle, \"flow is paused\");\n            break;\n        }\n        \n        //resume flow\n        NEFilterNewFlowVerdict* verdict = (flowVerdict == kFlowVerdictBlock)\n            ? [NEFilterNewFlowVerdict dropVerdict]\n            : [NEFilterNewFlowVerdict allowVerdict];\n        \n    \n        os_log_debug(logHandle, \"resuming related flow with %{public}@\", verdict);\n\n        [self resumeFlow:flow withVerdict:verdict];\n    }\n    \n    os_log_debug(logHandle, \"done processing related flows\");\n}\n\n//create process object\n-(Process*)createProcess:(NEFilterFlow*)flow\n{\n    //audit token\n    audit_token_t* token = NULL;\n    \n    //process obj\n    Process* process = nil;\n    \n    //extract (audit) token\n    token = (audit_token_t*)flow.sourceAppAuditToken.bytes;\n    \n    //init process object, via audit token\n    process = [[Process alloc] init:token];\n    if(nil == process)\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: failed to create process for %d\", audit_token_to_pid(*token));\n        \n        //bail\n        goto bail;\n    }\n    \n    //sync to add to cache\n    @synchronized(self.cache) {\n        \n        //add to cache\n        [self.cache setObject:process forKey:flow.sourceAppAuditToken];\n    }\n    \nbail:\n    \n    return process;\n}\n\n//get best hostname from flow\n// prioritizes domain names over IP addresses\n// uses same logic as active mode rule matching\n-(NSString*)getBestHostnameFromFlow:(NEFilterSocketFlow*)flow\n{\n    //best hostname\n    NSString* bestHostname = nil;\n    \n    //remote endpoint\n    NWHostEndpoint* remoteEndpoint = nil;\n    \n    //extract remote endpoint\n    remoteEndpoint = (NWHostEndpoint*)flow.remoteEndpoint;\n    \n    //priority 1: try flow.URL.host (best for domain names)\n    if(flow.URL.host.length)\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"using flow.URL.host as best hostname: %{public}@\", flow.URL.host);\n        \n        //use it\n        bestHostname = flow.URL.host;\n        \n        //done\n        goto bail;\n    }\n    \n    //priority 2: try flow.remoteHostname (macOS 11+)\n    if(@available(macOS 11, *))\n    {\n        if(flow.remoteHostname.length)\n        {\n            //dbg msg\n            os_log_debug(logHandle, \"using flow.remoteHostname as best hostname: %{public}@\", flow.remoteHostname);\n            \n            //use it\n            bestHostname = flow.remoteHostname;\n            \n            //done\n            goto bail;\n        }\n    }\n    \n    //priority 3: fallback to remoteEndpoint.hostname (may be IP address)\n    if(remoteEndpoint.hostname.length)\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"using remoteEndpoint.hostname as fallback hostname: %{public}@\", remoteEndpoint.hostname);\n        \n        //use it\n        bestHostname = remoteEndpoint.hostname;\n    }\n    \nbail:\n    \n    //dbg msg\n    os_log_debug(logHandle, \"best hostname for flow: %{public}@\", bestHostname);\n    \n    return bestHostname;\n}\n\n//check if hostname is a valid localhost address\n-(BOOL)isLocalhostHostname:(NSString*)hostname {\n    \n    struct sockaddr_in sa4 = {0};\n    struct sockaddr_in6 sa6 = {0};\n    \n    //sanity check\n    if(!hostname.length) {\n        return NO;\n    }\n    \n    //exact matches for localhost or IPv6 loopback\n    if([hostname isEqualToString:@\"::1\"] ||\n       [hostname isEqualToString:@\"localhost\"]) {\n        return YES;\n    }\n    \n    //check for valid IPv4 loopback range (127.0.0.0/8)\n    if(inet_pton(AF_INET, hostname.UTF8String, &(sa4.sin_addr)) == 1) {\n        return IN_LOOPBACK(ntohl(sa4.sin_addr.s_addr));\n    }\n    \n    //check for valid IPv6 loopback (::1)\n    if(inet_pton(AF_INET6, [hostname UTF8String], &(sa6.sin6_addr)) == 1) {\n        return IN6_IS_ADDR_LOOPBACK(&sa6.sin6_addr);\n    }\n    \n    //not a valid localhost address\n    return NO;\n}\n\n@end\n"
  },
  {
    "path": "LuLu/Extension/GrayList.h",
    "content": "//\n//  file: GrayList.h\n//  project: lulu (launch daemon)\n//  description: gray listed binaries (header)\n//\n//  created by Patrick Wardle\n//  copyright (c) 2017 Objective-See. All rights reserved.\n//\n\n@import OSLog;\n@import Foundation;\n\n\n@interface GrayList : NSObject\n\n/* PROPERTIES */\n\n//gray listed (apple) binaries\n@property(nonatomic, retain)NSMutableSet* graylistedBinaries;\n\n/* METHODS */\n//determine if process is graylisted\n-(BOOL)isGrayListed:(Process*)process;\n\n@end\n"
  },
  {
    "path": "LuLu/Extension/GrayList.m",
    "content": "//\n//  file: GrayList.m\n//  project: lulu (launch daemon)\n//  description: gray listed binaries\n//\n//  created by Patrick Wardle\n//  copyright (c) 2017 Objective-See. All rights reserved.\n//\n\n#import \"consts.h\"\n#import \"Process.h\"\n#import \"GrayList.h\"\n\n//apple system utils that aren't allowed by default\n// these may be abused by malware, so will make sure they trigger an alert\nNSString* const GRAYLISTED_BINARIES[] =\n{\n    @\"com.apple.nc\",\n    @\"com.apple.ftp\",\n    @\"com.apple.zsh\",\n    @\"com.apple.ksh\",\n    @\"com.apple.php\",\n    @\"com.apple.scp\",\n    @\"com.apple.ssh\",\n    @\"com.apple.bash\",\n    @\"com.apple.tcsh\",\n    @\"com.apple.curl\",\n    @\"com.apple.perl\",\n    @\"com.apple.ruby\",\n    @\"com.apple.sftp\",\n    @\"com.tcltk.tclsh\",\n    @\"com.apple.perl5\",\n    @\"com.apple.whois\",\n    @\"com.apple.python\",\n    @\"com.apple.telnet\",\n    @\"com.apple.openssh\",\n    @\"com.apple.python2\",\n    @\"com.apple.python3\",\n    @\"org.python.python\",\n    @\"com.apple.pythonw\",\n    @\"com.apple.osascript\",\n    \n};\n\n/* GLOBALS */\n\n//log handle\nextern os_log_t logHandle;\n\n@implementation GrayList\n\n@synthesize graylistedBinaries;\n\n//init\n-(id)init\n{\n    //init super\n    self = [super init];\n    if(nil != self)\n    {\n        //init list (set) of gray listed binaries\n        graylistedBinaries = [NSMutableSet set];\n\n        //add each to set\n        for(NSUInteger i=0; i<sizeof(GRAYLISTED_BINARIES)/sizeof(GRAYLISTED_BINARIES[0]); i++)\n        {\n            //add\n            [self.graylistedBinaries addObject:GRAYLISTED_BINARIES[i]];\n        }\n        \n        //dbg msg\n        os_log_debug(logHandle, \"loaded 'gray-listed' binaries: %{public}@\", self.graylistedBinaries);\n    }\n    \n    return self;\n}\n\n//determine if process is graylisted\n// a) signed by apple\n// b) signing identifier matches\n-(BOOL)isGrayListed:(Process*)process\n{\n    //flag\n    BOOL grayListed = NO;\n    \n    //dbg info\n    os_log_debug(logHandle, \"checking if %{public}@ is graylisted (signing info: %{public}@)\", process.path, process.csInfo);\n    \n    //no code signing identifier?\n    if(nil == process.csInfo[KEY_CS_ID]) goto bail;\n    \n    //has to be apple\n    if(Apple != [process.csInfo[KEY_CS_SIGNER] intValue]) goto bail;\n\n    //not in list?\n    if(YES != [self.graylistedBinaries containsObject:process.csInfo[KEY_CS_ID]])\n    {\n        //bail\n        goto bail;\n    }\n    \n    //item is gray listed\n    grayListed = YES;\n    \nbail:\n    \n    return grayListed;\n}\n\n@end\n"
  },
  {
    "path": "LuLu/Extension/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleDisplayName</key>\n\t<string>LuLu</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>$(MARKETING_VERSION)</string>\n\t<key>CFBundleVersion</key>\n\t<string>$(CURRENT_PROJECT_VERSION)</string>\n\t<key>LSMinimumSystemVersion</key>\n\t<string>$(MACOSX_DEPLOYMENT_TARGET)</string>\n\t<key>NSHumanReadableCopyright</key>\n\t<string>Copyright (c) 2020 Objective-See. All rights reserved.</string>\n\t<key>NSSystemExtensionUsageDescription</key>\n\t<string>LuLu needs to load its System Extension to block unauthorized network connections.</string>\n\t<key>NetworkExtension</key>\n\t<dict>\n\t\t<key>NEMachServiceName</key>\n\t\t<string>$(TeamIdentifierPrefix)com.objective-see.lulu</string>\n\t\t<key>NEProviderClasses</key>\n\t\t<dict>\n\t\t\t<key>com.apple.networkextension.filter-data</key>\n\t\t\t<string>FilterDataProvider</string>\n\t\t</dict>\n\t</dict>\n</dict>\n</plist>\n"
  },
  {
    "path": "LuLu/Extension/Preferences.h",
    "content": "//\n//  Preferences.h\n//  launchDaemon\n//\n//  Created by Patrick Wardle on 2/22/18.\n//  Copyright (c) 2018 Objective-See. All rights reserved.\n//\n\n@import OSLog;\n@import Foundation;\n\n@interface Preferences : NSObject\n\n/* PROPERTIES */\n\n//preferences\n@property(nonatomic, retain)NSMutableDictionary* preferences;\n\n/* METHODS */\n\n//load prefs from disk\n-(BOOL)load;\n\n//update prefs\n// saves and handles logic for specific prefs\n-(BOOL)update:(NSDictionary*)updates replace:(BOOL)replace;\n\n//save to disk\n-(BOOL)save;\n\n//get current profile\n// this is saved in the default preferences (and may be nil)\n-(NSString*)getCurrentProfile;\n\n//set current profile\n// this is saved in the default preferences (and may be nil)\n-(void)setCurrentProfile:(NSString*)profilePath;\n\n@end\n"
  },
  {
    "path": "LuLu/Extension/Preferences.m",
    "content": "//\n//  Preferences.m\n//  launchDaemon\n//\n//  Created by Patrick Wardle on 2/22/18.\n//  Copyright (c) 2018 Objective-See. All rights reserved.\n//\n\n#import \"consts.h\"\n#import \"BlockOrAllowList.h\"\n#import \"Preferences.h\"\n\n/* GLOBALS */\n\n//log handle\nextern os_log_t logHandle;\n\n//allow list\nextern BlockOrAllowList* allowList;\n\n//block list\nextern BlockOrAllowList* blockList;\n\n@implementation Preferences\n\n@synthesize preferences;\n\n//init\n// loads prefs\n-(id)init\n{\n    //super\n    self = [super init];\n    if(nil != self)\n    {\n        //default prefs exist?\n        // load them from disk\n        if(YES == [NSFileManager.defaultManager fileExistsAtPath:[INSTALL_DIRECTORY stringByAppendingPathComponent:PREFS_FILE]])\n        {\n            //load\n            if(YES != [self load])\n            {\n                //err msg\n                os_log_error(logHandle, \"ERROR: failed to loads preferences from %@\", PREFS_FILE);\n                \n                //unset\n                self = nil;\n                \n                //bail\n                goto bail;\n            }\n            \n        }\n        //no prefs (yet)\n        // just initialze empty dictionary\n        else\n        {\n            //init\n            self.preferences = [NSMutableDictionary dictionary];\n        }\n    }\n    \nbail:\n    \n    return self;\n}\n\n//get path to preferences\n// either default, or in current profile directory\n-(NSString*)path\n{\n    //current profile\n    NSString* currentProfile = nil;\n    \n    //path\n    // init with default\n    NSString* path = [INSTALL_DIRECTORY stringByAppendingPathComponent:PREFS_FILE];\n    \n    //not found?\n    // that ok, likely just first time\n    if(YES != [NSFileManager.defaultManager fileExistsAtPath:path])\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"default preferences file '%{public}@' not found ...first time?\", path);\n        \n        //done\n        goto bail;\n    }\n    \n    //get current profile\n    currentProfile = [self getCurrentProfile];\n    if(nil != currentProfile)\n    {\n        //set\n        path = [currentProfile stringByAppendingPathComponent:PREFS_FILE];\n    }\n    \nbail:\n    \n    //dbg msg\n    os_log_debug(logHandle, \"using preferences file: %{public}@\", path);\n    \n    return path;\n}\n\n//load prefs from disk\n-(BOOL)load\n{\n    //flag\n    BOOL loaded = NO;\n    \n    //path\n    NSString* prefsFile = [self path];\n    \n    //load\n    self.preferences = [NSMutableDictionary dictionaryWithContentsOfFile:prefsFile];\n    if(nil == self.preferences)\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: failed to load preference from %{public}@\", prefsFile);\n        goto bail;\n    }\n    \n    //dbg msg\n    os_log_debug(logHandle, \"from %{public}@, loaded preferences: %{public}@\", prefsFile, self.preferences);\n    \n    //set any defaults\n    [self setDefaults];\n    \n    //happy\n    loaded = YES;\n    \nbail:\n    \n    return loaded;\n}\n\n//set any defaults\n// needed as upgrades don't (re)display welcome window\n-(void)setDefaults {\n    \n    //flag\n    BOOL shouldSave = NO;\n    \n    //PREF_ALLOW_LOCALHOST: default to YES for existing users\n    if(!self.preferences[PREF_ALLOW_LOCALHOST]) {\n    \n        os_log_debug(logHandle, \"setting default value for PREF_ALLOW_LOCALHOST: YES\");\n        \n        //set default\n        self.preferences[PREF_ALLOW_LOCALHOST] = @YES;\n        shouldSave = YES;\n    }\n    \n    //could add any others here...\n    \n    //save\n    if(shouldSave) {\n        [self save];\n    }\n}\n\n//update prefs\n// handles logic for specific prefs & then saves\n-(BOOL)update:(NSDictionary*)updates replace:(BOOL)replace\n{\n    //flag\n    BOOL updated = NO;\n    \n    //allow list\n    NSString* allowListPath = nil;\n    \n    //block list\n    NSString* blockListPath = nil;\n    \n    //sync\n    @synchronized (self) {\n\n    //replace?\n    // e.g. new profile\n    if(YES == replace)\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"replacing preferences (%{public}@)\", updates);\n        \n        //replace\n        self.preferences = [updates mutableCopy];\n    }\n    //merge\n    else\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"updating preferences (%{public}@)\", updates);\n        \n        //add in (new) prefs\n        [self.preferences addEntriesFromDictionary:updates];\n    }\n        \n    //save\n    if(YES != [self save])\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: failed to save preferences\");\n        \n        //bail\n        goto bail;\n    }\n\n    //extract any allow list\n    allowListPath = updates[PREF_ALLOW_LIST];\n    \n    //extract any block list\n    blockListPath = updates[PREF_BLOCK_LIST];\n    \n    //(new) allow list?\n    // now, trigger reload\n    if(0 != [allowListPath length])\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"user specified new 'allow' list: %{public}@\", allowListPath);\n        \n        //first time?\n        if(nil == allowList)\n        {\n            //alloc/init/load block list\n            allowList = [[BlockOrAllowList alloc] init:allowListPath];\n        }\n        //otherwise just reload\n        else\n        {\n            //(re)load\n            [allowList load:allowListPath];\n        }\n    }\n    \n    //(new) block list?\n    // now, trigger reload\n    if(0 != [blockListPath length])\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"user specified new 'block' list: %{public}@\", blockListPath);\n        \n        //first time?\n        if(nil == blockList)\n        {\n            //alloc/init/load block list\n            blockList = [[BlockOrAllowList alloc] init:blockListPath];\n        }\n        //otherwise just reload\n        else\n        {\n            //(re)load\n            [blockList load:blockListPath];\n        }\n    }\n    \n    //happy\n    updated = YES;\n        \n    } //sync\n    \nbail:\n    \n    return updated;\n}\n\n//save to disk\n-(BOOL)save\n{\n    //flag\n    BOOL wasSaved = NO;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"method '%s' invoked\", __PRETTY_FUNCTION__);\n    \n    //init w/ default\n    NSString* prefsFile = [self path];\n    \n    //write out preferences\n    if(YES != [self.preferences writeToFile:prefsFile atomically:YES])\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: failed to save preferences to: %{public}@\", prefsFile);\n        goto bail;\n    }\n    \n    //dbg msg\n    os_log_debug(logHandle, \"saved preferences to %{public}@\", prefsFile);\n    \n    //happy\n    wasSaved = YES;\n    \nbail:\n    \n    return wasSaved;\n}\n\n//get current profile\n// this is saved in the default preferences (and may be nil)\n-(NSString*)getCurrentProfile\n{\n    //current\n    NSString* currentProfile = nil;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"method '%s' invoked\", __PRETTY_FUNCTION__);\n    \n    //load *default* prefs\n    NSDictionary* defaultPreferences = [NSDictionary dictionaryWithContentsOfFile:[INSTALL_DIRECTORY stringByAppendingPathComponent:PREFS_FILE]];\n    \n    //extract\n    currentProfile = defaultPreferences[PREF_CURRENT_PROFILE];\n    \n    //dbg msg\n    os_log_debug(logHandle, \"returning current profile %{public}@\", currentProfile);\n    \n    return currentProfile;\n}\n\n//set current profile\n// this is saved in the *default* preferences (and may be nil)\n-(void)setCurrentProfile:(NSString*)profilePath\n{\n    //default pref's file\n    NSString* defaultPreferencesFile = [INSTALL_DIRECTORY stringByAppendingPathComponent:PREFS_FILE];\n    \n    //load *default* prefs\n    NSMutableDictionary* defaultPreferences = [NSMutableDictionary dictionaryWithContentsOfFile:defaultPreferencesFile];\n    \n    //set\n    defaultPreferences[PREF_CURRENT_PROFILE] = profilePath;\n    \n    //save\n    [defaultPreferences writeToFile:defaultPreferencesFile atomically:YES];\n    \n    //dbg msg\n    os_log_debug(logHandle, \"set current profile to %{public}@\", profilePath);\n    \n    return;\n}\n\n@end\n"
  },
  {
    "path": "LuLu/Extension/Process.h",
    "content": "//\n//  Process.h\n//  LuLu\n//\n//  Created by Patrick Wardle on 8/27/20.\n//  Copyright (c) 2020 Objective-See. All rights reserved.\n//\n\n#ifndef Process_h\n#define Process_h\n\n@import OSLog;\n\n#import \"Binary.h\"\n\n@interface Process : NSObject\n\n/* PROPERTIES */\n\n//pid\n@property pid_t pid;\n\n//user id\n@property uid_t uid;\n\n//type\n// used by process mon\n@property u_int16_t type;\n\n//exit code\n@property u_int32_t exit;\n\n//(self) deleted binary\n@property BOOL deleted;\n\n//name\n@property(nonatomic, retain)NSString* _Nullable name;\n\n//path\n@property(nonatomic, retain)NSString* _Nullable path;\n\n//args\n@property(nonatomic, retain)NSMutableArray* _Nullable arguments;\n\n//ancestors\n@property(nonatomic, retain)NSMutableArray* _Nullable ancestors;\n\n//signing info\n@property(nonatomic, retain)NSMutableDictionary* _Nullable csInfo;\n\n//key\n@property(nonatomic, retain)NSString* _Nonnull key;\n\n//Binary object\n// has path, hash, etc\n@property(nonatomic, retain)Binary* _Nonnull binary;\n\n//timestamp\n@property(nonatomic, retain)NSDate* _Nonnull timestamp;\n\n/* METHODS */\n\n//init with a audit token\n// method will then (try) fill out rest of object\n-(id _Nullable)init:(audit_token_t* _Nonnull)token;\n\n@end\n\n#endif /* Process_h */\n"
  },
  {
    "path": "LuLu/Extension/Process.m",
    "content": "//\n//  File: Process.m\n//  Project: Lulu\n//\n//  Created by: Patrick Wardle\n//  Copyright:  2017 Objective-See\n//\n\n#import \"signing.h\"\n#import \"Process.h\"\n#import \"Utilities.h\"\n\n#import <dlfcn.h>\n#import <libproc.h>\n#import <bsm/libbsm.h>\n#import <sys/sysctl.h>\n\n/* GLOBALS */\n\n//log handle\nextern os_log_t logHandle;\n\n@implementation Process\n\n@synthesize pid;\n@synthesize exit;\n@synthesize path;\n@synthesize csInfo;\n@synthesize ancestors;\n@synthesize arguments;\n@synthesize timestamp;\n\n//init\n-(id)init\n{\n    //init super\n    self = [super init];\n    if(nil != self)\n    {\n        //alloc array for args\n        arguments = [NSMutableArray array];\n        \n        //alloc array for parents\n        ancestors = [NSMutableArray array];\n            \n        //set start time\n        timestamp = [NSDate date];\n        \n        //init pid\n        self.pid = -1;\n        \n        //init user\n        self.uid = -1;\n        \n        //init exit\n        self.exit = -1;\n    }\n    \n    return self;\n}\n\n//init with a token / pid\n// method will then (try) fill out rest of object\n-(id)init:(audit_token_t*)token\n{\n    //current token\n    NSData* currentToken = nil;\n    \n    //init self/super\n    self = [self init];\n    if(self)\n    {\n        //save pid\n        self.pid = audit_token_to_pid(*token);\n        if(0 == self.pid)\n        {\n            //err msg\n            os_log_error(logHandle, \"ERROR: 'audit_token_to_pid' returned NULL\\n\");\n            return nil;\n        }\n        \n        //get path\n        // also sets 'self.deleted' iVar\n        [self getPath:token];\n        if(0 == self.path.length)\n        {\n            //err msg\n            os_log_error(logHandle, \"ERROR: failed to find path for process %d\\n\", self.pid);\n            return nil;\n        }\n        \n        //set name\n        //name for normal procs\n        if(YES != self.deleted)\n        {\n            //get/add\n            self.name = getProcessName(0, self.path);\n        }\n        //for delete procs\n        // get path via pid\n        else\n        {\n            //get/add\n            self.name = getProcessName(self.pid, self.path);\n        }\n        \n        //get user\n        self.uid = audit_token_to_euid(*token);\n        \n        //generate (dynamic) code information\n        [self generateSigningInfo:token];\n        \n        //generate key\n        // based on cs info, or path\n        self.key = [self generateKey];\n        \n        //init binary\n        self.binary = [[Binary alloc] init:self.path];\n        \n        /* pid specific logic\n           note: pids can wrap,\n           so we check audit token is still same!\n         */\n        \n        //set args\n        [self getArgs];\n        \n        //enum ancestors\n        self.ancestors = generateProcessHierarchy(self.pid);\n        \n        //grab current (audit) token\n        currentToken = tokenForPid(self.pid);\n        if(0 != currentToken.length)\n        {\n            //check!\n            // if it's changed, means pid points to new process, so unset parent, args, etc as these may be invalid!\n            if(audit_token_to_pidversion(*token) != audit_token_to_pidversion(*(audit_token_t*)currentToken.bytes))\n            {\n                //err msg\n                os_log_error(logHandle, \"ERROR: audit token mismatch ...pid re-used?\");\n                \n                //unset\n                arguments = nil;\n                ancestors = nil;\n            }\n        }\n    }\n        \n    return self;\n}\n\n//generate key\n// note: this matches rules' generate key algo\n-(NSString*)generateKey\n{\n    //id\n    NSString* key = nil;\n    \n    //signer\n    NSInteger signer = None;\n    \n    //cs info?\n    if(nil != self.csInfo)\n    {\n        //extract signer\n        signer = [self.csInfo[KEY_CS_SIGNER] intValue];\n        \n        //apple/app store\n        // just use cs id\n        if( (Apple == signer) ||\n            (AppStore == signer) )\n        {\n            //set key\n            key = self.csInfo[KEY_CS_ID];\n        }\n        \n        //dev id?\n        // use cs id + (leaf) signer\n        else if(DevID == signer)\n        {\n            //check for cs id/auths\n            if( (0 != [self.csInfo[KEY_CS_ID] length]) &&\n                (0 != [self.csInfo[KEY_CS_AUTHS] count]) )\n            {\n                //set\n                key = [NSString stringWithFormat:@\"%@:%@\", self.csInfo[KEY_CS_ID], [self.csInfo[KEY_CS_AUTHS] firstObject]];\n            }\n        }\n    }\n        \n    //no valid cs info, etc\n    // just use item's path\n    if(0 == key.length)\n    {\n        //set\n        key = self.path;\n    }\n    \n    //dbg msg\n    os_log_debug(logHandle, \"generated process key: %{public}@\", key);\n\n    return key;\n}\n\n//set process's path\n-(void)getPath:(audit_token_t*)token\n{\n    //status\n    OSStatus status = !errSecSuccess;\n    \n    //code ref\n    SecCodeRef code = NULL;\n    \n    //path\n    CFURLRef path = nil;\n    \n    //obtain code ref\n    status = SecCodeCopyGuestWithAttributes(NULL, (__bridge CFDictionaryRef _Nullable)(@{(__bridge NSString *)kSecGuestAttributeAudit:[NSData dataWithBytes:token length:sizeof(audit_token_t)]}), kSecCSDefaultFlags, &code);\n    if(errSecSuccess == status)\n    {\n        //copy path\n        status = SecCodeCopyPath(code, kSecCSDefaultFlags, &path);\n        if(errSecSuccess == status)\n        {\n            //extract/copy path\n            self.path = [((__bridge NSURL*)path).path copy];\n        }\n        //err msg\n        else\n        {\n            //err msg\n            os_log_error(logHandle, \"ERROR: 'SecCodeCopyPath' failed with': %#x\", status);\n        }\n    }\n    //err msg\n    else\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: 'SecCodeCopyGuestWithAttributes' failed with': %#x\", status);\n    }\n    \n    //process's binary deleted?\n    if(kPOSIXErrorENOENT == status)\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"process %d's binary appears to be deleted\", pid);\n        \n        //set flag\n        self.deleted = YES;\n    }\n\n    //path (still) nil?\n    // try other methods\n    if(nil == path)\n    {\n        //get path via pid\n        self.path = getProcessPath(self.pid);\n    }\n    \n    //resolve symlinks\n    self.path = [self.path stringByResolvingSymlinksInPath];\n    \n    //free path\n    if(NULL != path)\n    {\n        //free\n        CFRelease(path);\n        path = NULL;\n    }\n    \n    //free code ref\n    if(NULL != code)\n    {\n        //free\n        CFRelease(code);\n        code = NULL;\n    }\n    \n    return;\n}\n\n//extract commandline args\n// saves into 'arguments' ivar\n-(void)getArgs\n{\n    //'management info base' array\n    int mib[3] = {0};\n    \n    //system's size for max args\n    int systemMaxArgs = 0;\n    \n    //process's args\n    char* processArgs = NULL;\n    \n    //# of args\n    int numberOfArgs = 0;\n    \n    //arg\n    NSString* argument = nil;\n    \n    //start of (each) arg\n    char* argStart = NULL;\n    \n    //size of buffers, etc\n    size_t size = 0;\n    \n    //parser pointer\n    char* parser = NULL;\n    \n    //init mib\n    // want system's size for max args\n    mib[0] = CTL_KERN;\n    mib[1] = KERN_ARGMAX;\n    \n    //set size\n    size = sizeof(systemMaxArgs);\n    \n    //get system's size for max args\n    if(-1 == sysctl(mib, 2, &systemMaxArgs, &size, NULL, 0))\n    {\n        //bail\n        goto bail;\n    }\n    \n    //alloc space for args\n    processArgs = malloc(systemMaxArgs);\n    if(NULL == processArgs)\n    {\n        //bail\n        goto bail;\n    }\n    \n    //init mib\n    // want process args\n    mib[0] = CTL_KERN;\n    mib[1] = KERN_PROCARGS2;\n    mib[2] = pid;\n    \n    //set size\n    size = (size_t)systemMaxArgs;\n    \n    //get process's args\n    if(-1 == sysctl(mib, 3, processArgs, &size, NULL, 0))\n    {\n        //bail\n        goto bail;\n    }\n    \n    //sanity check\n    // ensure buffer is somewhat sane\n    if(size <= sizeof(int))\n    {\n        //bail\n        goto bail;\n    }\n    \n    //extract number of args\n    // at start of buffer\n    memcpy(&numberOfArgs, processArgs, sizeof(numberOfArgs));\n    \n    //init pointer to start of args\n    // they start right after # of args\n    parser = processArgs + sizeof(numberOfArgs);\n    \n    //scan until end of process's NULL-terminated path\n    while(parser < &processArgs[size])\n    {\n        //scan till NULL-terminator\n        if(0x0 == *parser)\n        {\n            //end of exe name\n            break;\n        }\n        \n        //next char\n        parser++;\n    }\n    \n    //sanity check\n    // make sure end-of-buffer wasn't reached\n    if(parser == &processArgs[size])\n    {\n        //bail\n        goto bail;\n    }\n    \n    //skip all trailing NULLs\n    // scan will end when non-NULL is found\n    while(parser < &processArgs[size])\n    {\n        //scan till NULL-terminator\n        if(0x0 != *parser)\n        {\n            //ok, got to argv[0]\n            break;\n        }\n        \n        //next char\n        parser++;\n    }\n    \n    //sanity check\n    // (again), make sure end-of-buffer wasn't reached\n    if(parser == &processArgs[size])\n    {\n        //bail\n        goto bail;\n    }\n    \n    //parser should now point to argv[0], process name\n    // init arg start\n    argStart = parser;\n    \n    //keep scanning until all args are found\n    // each is NULL-terminated\n    while(parser < &processArgs[size])\n    {\n        //each arg is NULL-terminated\n        // so scan till NULL, then save into array\n        if(*parser == '\\0')\n        {\n            //save arg\n            if(NULL != argStart)\n            {\n                //try convert\n                // ignore (if not UTF8, etc...)\n                argument = [NSString stringWithUTF8String:argStart];\n                if(nil != argument)\n                {\n                    //save\n                    [self.arguments addObject:argument];\n                }\n            }\n            \n            //init string pointer to (possibly) next arg\n            argStart = ++parser;\n            \n            //bail if we've hit arg cnt\n            if(self.arguments.count == numberOfArgs)\n            {\n                //bail\n                break;\n            }\n        }\n        \n        //next char\n        parser++;\n    }\n    \nbail:\n    \n    //free process args\n    if(NULL != processArgs)\n    {\n        //free\n        free(processArgs);\n        \n        //unset\n        processArgs = NULL;\n    }\n    \n    return;\n}\n\n//generate signing info\n-(void)generateSigningInfo:(audit_token_t*)token\n{\n    //signing info\n    NSMutableDictionary* extractedSigningInfo = nil;\n    \n    //extract signing info\n    extractedSigningInfo = extractSigningInfo(token, nil, kSecCSDefaultFlags);\n    \n    //valid?\n    // save into iVar\n    if( (nil != extractedSigningInfo[KEY_CS_STATUS]) &&\n        (noErr == [extractedSigningInfo[KEY_CS_STATUS] intValue]))\n    {\n        //save\n        self.csInfo = extractedSigningInfo;\n    }\n    //invalid\n    else\n    {\n        //error msg\n        os_log_error(logHandle, \"ERROR: invalid code signing information for %{public}@: %{public}@\", self.path, extractedSigningInfo);\n    }\n\n    return;\n}\n\n//for pretty printing\n-(NSString *)description\n{\n    //pretty print\n    return [NSString stringWithFormat: @\"pid: %d\\npath: %@\\nuser: %d\\nargs: %@\\nancestors: %@\\n signing info: %@\\n binary:\\n%@\", self.pid, self.path, self.uid, self.arguments, self.ancestors, self.csInfo, self.binary];\n}\n\n@end\n"
  },
  {
    "path": "LuLu/Extension/Profiles.h",
    "content": "//\n//  Profiles.h\n//\n//  Created by Patrick Wardle on 06/21/25.\n//  Copyright (c) 2025 Objective-See. All rights reserved.\n//\n\n@import OSLog;\n@import Foundation;\n\n@interface Profiles : NSObject\n\n/* PROPERTIES */\n\n//profiles directory\n@property(nonatomic, retain)NSString* directory;\n\n/* METHODS */\n\n-(NSMutableArray*)enumerate;\n-(void)set:(NSString*)profilePath;\n-(BOOL)add:(NSString*)name preferences:(NSDictionary*)preferences;\n-(BOOL)delete:(NSString*)name;\n\n@end\n"
  },
  {
    "path": "LuLu/Extension/Profiles.m",
    "content": "//\n//  Profiles.m\n//\n//  Created by Patrick Wardle on 06/21/25.\n//  Copyright (c) 2025 Objective-See. All rights reserved.\n//\n\n#import \"Rules.h\"\n#import \"consts.h\"\n#import \"Profiles.h\"\n#import \"Preferences.h\"\n\n/* GLOBALS */\n\n//log handle\nextern os_log_t logHandle;\n\n//rules\nextern Rules* rules;\n\n//preferences\nextern Preferences* preferences;\n\n@implementation Profiles\n\n//init\n// loads profiles\n-(id)init\n{\n    //super\n    self = [super init];\n    if(nil != self)\n    {\n        //set (base) directory\n        self.directory = [INSTALL_DIRECTORY stringByAppendingPathComponent:PROFILE_DIRECTORY];\n    }\n        \n    return self;\n}\n\n//enumerate\n// return list of just profile *names*\n-(NSMutableArray*)enumerate\n{\n    //list\n    NSMutableArray* profiles = [NSMutableArray array];\n    \n    //no profiles?\n    // not problem, but just bail here\n    if(![NSFileManager.defaultManager fileExistsAtPath:self.directory])\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"no profiles? didn't find profiles directory %{public}@\", self.directory);\n        goto bail;\n    }\n\n    //grab all items, saving only names of directories\n    for(NSString* name in [NSFileManager.defaultManager contentsOfDirectoryAtPath:self.directory error:nil])\n    {\n        BOOL isDir = NO;\n        NSString* fullPath = [self.directory stringByAppendingPathComponent:name];\n        \n        //add if directory\n        if([NSFileManager.defaultManager fileExistsAtPath:fullPath isDirectory:&isDir] && isDir)\n        {\n            //add\n            [profiles addObject:name];\n        }\n    }\n    \n    //sort for UI\n    [profiles sortUsingSelector:@selector(localizedCaseInsensitiveCompare:)];\n\n    //dbg msg\n    os_log_debug(logHandle, \"profiles: %{public}@\", profiles);\n    \nbail:\n    \n    return profiles;\n}\n\n//add new profile\n// and then set it to default\n-(BOOL)add:(NSString*)name preferences:(NSDictionary*)newPreferences\n{\n    BOOL wasAdded = NO;\n    NSError* error = nil;\n    NSString *newProfilePath = nil;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"method '%s' invoked with %{public}@ / %{public}@\", __PRETTY_FUNCTION__, name, newPreferences);\n\n    //create base profiles directory if needed\n    if(YES != [NSFileManager.defaultManager fileExistsAtPath:self.directory])\n    {\n        //create\n        if(YES != [NSFileManager.defaultManager createDirectoryAtPath:self.directory withIntermediateDirectories:YES attributes:nil error:&error])\n        {\n            //error\n            os_log_error(logHandle, \"ERROR: failed to create profiles directory '%{public}@': %{public}@\",\n                         self.directory, error.localizedDescription);\n            goto bail;\n        }\n    }\n    \n    //init path for new profile directory\n    newProfilePath = [[[self.directory stringByAppendingPathComponent:name.lastPathComponent] stringByStandardizingPath] stringByResolvingSymlinksInPath];\n    \n    //sanity check\n    if(YES != [newProfilePath hasPrefix:[self.directory stringByAppendingString:@\"/\"]]) {\n        \n        //error\n        os_log_error(logHandle, \"ERROR: created path '%{public}@' isn't in the profile directory %{public}@\",\n                     newProfilePath, self.directory);\n        goto bail;\n    }\n    \n    //if already exists, delete it\n    if(YES == [NSFileManager.defaultManager fileExistsAtPath:newProfilePath]) {\n        \n        //remove install directory\n        if(YES != [NSFileManager.defaultManager removeItemAtPath:newProfilePath error:&error])\n        {\n            //err msg\n            os_log_error(logHandle, \"ERROR: failed to remove existing profile %{public}@ (error: %{public}@)\", newProfilePath, error);\n        }\n        else\n        {\n            //dbg msg\n            os_log_debug(logHandle, \"removed existing profile %{public}@\", newProfilePath);\n        }\n    }\n    \n    //create directory for new profile\n    if(YES != [NSFileManager.defaultManager createDirectoryAtPath:newProfilePath withIntermediateDirectories:NO attributes:nil error:&error])\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: Failed to create new profile directory '%{public}@': %{public}@\",\n                     newProfilePath, error.localizedDescription);\n        goto bail;\n    }\n    \n    //dbg msg\n    os_log_debug(logHandle, \"created profile directory: %{public}@\", newProfilePath);\n    \n    //set as current\n    [self set:newProfilePath];\n    \n    //save new prefs\n    // replacing all\n    [preferences update:newPreferences replace:YES];\n    \n    //clear out all rules\n    @synchronized (rules) {\n        \n        [rules.rules removeAllObjects];\n    }\n    \n    //generate default rules\n    if(YES != [rules generateDefaultRules])\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: failed to generate default rules\");\n        \n        //bail\n        goto bail;\n    }\n    \n    //save\n    [rules save];\n    \n    //reload rules\n    [rules load];\n    \n    //reload prefs\n    [preferences load];\n\n    //happy\n    wasAdded = YES;\n    \nbail:\n    \n    return wasAdded;\n}\n\n//set current profile path in *default* prefs\n// note: can be called with nil to reset back to default profile\n-(void)set:(NSString*)profilePath\n{\n    //set\n    [preferences setCurrentProfile:profilePath];\n    \n    return;\n}\n\n//delete a profile\n// delete folder matching name and reset to default if needed\n-(BOOL)delete:(NSString*)name\n{\n    //flag\n    BOOL wasDeleted = NO;\n    \n    //error\n    NSError* error = nil;\n    \n    //current\n    NSString* current = nil;\n    \n    //path\n    NSString* profile = [self.directory stringByAppendingPathComponent:name];\n    \n    //dbg msg\n    os_log_debug(logHandle, \"deleting profile directory: %{public}@\", profile);\n    \n    //flag\n    if(YES != [NSFileManager.defaultManager removeItemAtPath:profile error:&error])\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: Failed to delete profile directory '%{public}@': %{public}@\",\n                     profile, error.localizedDescription);\n        goto bail;\n    }\n    \n    //dbg msg\n    os_log_debug(logHandle, \"deleted profile directory: %{public}@\", profile);\n    \n    //get current\n    current = [preferences getCurrentProfile];\n    \n    //dbg msg\n    os_log_debug(logHandle, \"checking if %{public}@ matches current %{public}@\", profile, current);\n    \n    //was current?\n    if(YES == [profile isEqualToString:current])\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"'%{public}@' was current profile, so will reset back to default\", profile);\n        \n        //unset path\n        [self set:nil];\n        \n        //reload rules\n        [rules load];\n        \n        //reload prefs\n        [preferences load];\n    }\n    \n    //happy\n    wasDeleted = YES;\n    \nbail:\n    \n    return wasDeleted;\n}\n\n@end\n"
  },
  {
    "path": "LuLu/Extension/Rules.h",
    "content": "//\n//  file: Rules.h\n//  project: LuLu (launch daemon)\n//  description: handles rules & actions such as add/delete (header)\n//\n//  created by Patrick Wardle\n//  copyright (c) 2017 Objective-See. All rights reserved.\n//\n\n\n#ifndef Rules_h\n#define Rules_h\n\n#import \"Process.h\"\n#import \"XPCUserClient.h\"\n\n@import OSLog;\n@import Foundation;\n@import NetworkExtension;\n\n@class Rule;\n\n\n@interface Rules : NSObject\n{\n    \n}\n\n/* PROPERTIES */\n\n//rules\n@property(nonatomic, retain)NSMutableDictionary* rules;\n\n//xpc client for talking to login item\n@property(nonatomic, retain)XPCUserClient* xpcUserClient;\n\n/* METHODS */\n\n//prepare\n// first time? generate defaults rules\n// upgrade (v1.0)? convert to new format\n-(BOOL)prepare;\n\n//load from disk\n-(BOOL)load;\n\n//generate default rules\n-(BOOL)generateDefaultRules;\n\n//add a rule\n-(BOOL)add:(Rule*)rule save:(BOOL)save;\n\n//find (matching) rule\n-(Rule*)find:(Process*)process flow:(NEFilterSocketFlow*)flow csChange:(BOOL*)csChange;\n\n//disable (or re-enable)\n-(BOOL)toggleRule:(NSString*)key rule:(NSString*)uuid state:(NSNumber*)state;\n\n//delete rule\n-(BOOL)delete:(NSString*)key rule:(NSString*)uuid;\n\n//save\n-(BOOL)save;\n\n//import rules\n-(BOOL)import:(NSData*)rules userOnly:(BOOL)userOnly;\n\n//update an item's cs info\n// and also the cs info of all its rule\n-(void)updateCSInfo:(Process*)process;\n\n//cleanup rules\n-(NSUInteger)cleanup:(BOOL)full;\n\n@end\n\n#endif /* Rules_h */\n"
  },
  {
    "path": "LuLu/Extension/Rules.m",
    "content": "//\n//  file: Rules.m\n//  project: LuLu (launch daemon)\n//  description: handles rules & actions such as add/delete\n//\n//  created by Patrick Wardle\n//  copyright (c) 2017 Objective-See. All rights reserved.\n//\n\n#import \"Rule.h\"\n#import \"Rules.h\"\n#import \"Alerts.h\"\n#import \"consts.h\"\n#import \"Process.h\"\n#import \"utilities.h\"\n#import \"Preferences.h\"\n\n//default systems 'allow' rules\nNSString* const DEFAULT_RULES[] =\n{\n    @\"/System/Library/PrivateFrameworks/ApplePushService.framework/apsd\",\n    @\"/System/Library/PrivateFrameworks/AssistantServices.framework/Versions/A/Support/assistantd\",\n    @\"/usr/sbin/automount\",\n    @\"/System/Library/PrivateFrameworks/HelpData.framework/Versions/A/Resources/helpd\",\n    @\"/usr/sbin/mDNSResponder\",\n    @\"/sbin/mount_nfs\",\n    @\"/usr/libexec/mount_url\",\n    @\"/usr/sbin/ocspd\",\n    @\"/usr/bin/sntp\",\n    @\"/usr/libexec/trustd\"\n};\n\n/* format of rules\n    dictionary of dictionaries\n    key: signing id or item path (if unsigned)\n    values: dictionary with:\n        key: 'rules':\n        value: array of rules\n \n        key: 'csFlags':\n        value: item's code signing flags\n*/\n\n/* GLOBALS */\n\n//log handle\nextern os_log_t logHandle;\n\n//alerts obj\nextern Alerts* alerts;\n\n//prefs obj\nextern Preferences* preferences;\n\n@implementation Rules\n\n@synthesize rules;\n@synthesize xpcUserClient;\n\n//init method\n-(id)init\n{\n    //init super\n    self = [super init];\n    if(nil != self)\n    {\n        //alloc rules dictionary\n        rules = [NSMutableDictionary dictionary];\n        \n        //init XPC client\n        xpcUserClient = [[XPCUserClient alloc] init];\n    }\n    \n    return self;\n}\n\n//prepare\n// first time? generate defaults rules\n// upgrade (v1.0)? convert to new format\n-(BOOL)prepare\n{\n    //flag\n    BOOL prepared = NO;\n\n    //error\n    NSError* error = nil;\n    \n    //old rule's file\n    NSString* rulesFile_V1 = nil;\n    \n    //rule's file\n    NSString* rulesFile = nil;\n    \n    //init path to old rule's file\n    rulesFile_V1 = [INSTALL_DIRECTORY stringByAppendingPathComponent:RULES_FILE_V1];\n    \n    //init path to rule's file\n    rulesFile = [INSTALL_DIRECTORY stringByAppendingPathComponent:RULES_FILE];\n    \n    //first check for old rules\n    // ...and then upgrade to v2 format\n    if(YES == [[NSFileManager defaultManager] fileExistsAtPath:rulesFile_V1])\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"found v1.0 rules: %{public}@\", rulesFile_V1);\n        \n        //upgrade\n        if(YES != [self upgrade:[NSDictionary dictionaryWithContentsOfFile:rulesFile_V1]])\n        {\n            //err msg\n            os_log_error(logHandle, \"ERROR: failed to upgrade rules\");\n            \n            //but continue\n            // will revert to generating default rules\n        }\n        \n        //always delete rule v1.0 file\n        if(YES != [NSFileManager.defaultManager removeItemAtPath:rulesFile_V1 error:&error])\n        {\n            //err msg\n            os_log_error(logHandle, \"ERROR: failed to removed v1.0 rules: %{public}@\", rulesFile_V1);\n            \n        } else os_log_debug(logHandle, \"removed v1.0 rules: %{public}@\", rulesFile_V1);\n        \n    } else os_log_debug(logHandle, \"no v1.0 rules...\");\n    \n    //(still) no rules?\n    // first time, so generate default rules\n    if(YES != [[NSFileManager defaultManager] fileExistsAtPath:rulesFile])\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"no rules found\");\n        \n        //generate\n        if(YES != [self generateDefaultRules])\n        {\n            //err msg\n            os_log_error(logHandle, \"ERROR: failed to generate default rules\");\n            \n            //bail\n            goto bail;\n        }\n        \n        //save (generated rules)\n        if(YES != [self save])\n        {\n            //err msg\n            os_log_error(logHandle, \"ERROR: failed to save (generated) rules\");\n            \n            //bail\n            goto bail;\n        }\n\n        //dbg msg\n        os_log_debug(logHandle, \"done generating/saving default rules\");\n    }\n    \n    //happy\n    prepared = YES;\n\nbail:\n    \n    return prepared;\n}\n    \n//upgrade rules from v1.0\n// note: delete rules for paths the don't exist\n-(BOOL)upgrade:(NSDictionary*)rules_v1\n{\n    //flag\n    BOOL upgraded = NO;\n\n    //dbg msg\n    os_log_debug(logHandle, \"upgrading v1 rules...\");\n\n    //upgrade all rules\n    for(NSString* key in rules_v1)\n    {\n        //value\n        NSDictionary* value = nil;\n        \n        //code signing info\n        NSMutableDictionary* csInfo = nil;\n        \n        //info\n        NSMutableDictionary* info = nil;\n        \n        //item doesn't exit?\n        // just ignore it, and continue\n        if(YES != [[NSFileManager defaultManager] fileExistsAtPath:key])\n        {\n            //dbg msg\n            os_log_debug(logHandle, \"ignoring (v1) rule for %{public}@, as it no longer exists on disk\", key);\n            \n            //ignore\n            continue;\n        }\n        \n        //extact value\n        value = rules_v1[key];\n        \n        //init info\n        info = [NSMutableDictionary dictionary];\n        \n        //add path\n        info[KEY_PATH] = key;\n        \n        //add action\n        info[KEY_ACTION] = value[KEY_ACTION];\n        \n        //add type\n        info[KEY_TYPE] = value[KEY_TYPE];\n        \n        //extact cs info\n        csInfo = [value[KEY_CS_INFO] mutableCopy];\n        \n        //remove entitlments\n        // not needed and can be loooong\n        csInfo[KEY_CS_ENTITLEMENTS] = nil;\n    \n        //add cs info\n        if(nil != csInfo)\n        {\n            //add\n            info[KEY_CS_INFO] = csInfo;\n        }\n            \n        //add\n        // note: will save after loop\n        if(YES != [self add:[[Rule alloc] init:info] save:NO])\n        {\n            //err msg\n            os_log_error(logHandle, \"ERROR: failed to add rule\");\n            \n            //skip\n            continue;\n        }\n    }\n    \n    //save\n    if(YES != [self save])\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: failed to save v1 -> v2 rules\");\n        \n        //bail\n        goto bail;\n    }\n    \n    //happy\n    upgraded = YES;\n    \nbail:\n    \n    return upgraded;\n}\n\n//get rule's path\n// either default, or one in current profile\n-(NSString*)getPath\n{\n    //path\n    NSString* path = nil;\n    \n    //current profile\n    NSString* currentProfile =  [preferences getCurrentProfile];\n    \n    //init path to rule's file\n    // which might be in a profile directory\n    if(nil != currentProfile)\n    {\n        path = [currentProfile stringByAppendingPathComponent:RULES_FILE];\n    }\n    //otherwise default\n    else\n    {\n        //init w/ default\n        path = [INSTALL_DIRECTORY stringByAppendingPathComponent:RULES_FILE];\n    }\n    \n    return path;\n}\n\n//load rules from disk\n// either default location, or from current profile\n-(BOOL)load\n{\n    //result\n    BOOL result = NO;\n    \n    //error\n    NSError* error = nil;\n    \n    //rule's file\n    NSString* rulesFile = nil;\n    \n    //archived rules\n    NSData* archivedRules = nil;\n    \n    //item rules\n    NSArray* itemRules = nil;\n    \n    //interval for expirations\n    NSTimeInterval timeInterval = 0;\n    \n    //init path\n    rulesFile = [self getPath];\n    \n    //dbg msg\n    os_log_debug(logHandle, \"loading rules from: %{public}@\", rulesFile);\n    \n    //(now) load archived rules from disk\n    archivedRules = [NSData dataWithContentsOfFile:rulesFile];\n    if(nil == archivedRules)\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: failed to load rules from %{public}@\", rulesFile);\n        \n        //bail\n        goto bail;\n    }\n    \n    //unarchive\n    self.rules = [NSKeyedUnarchiver unarchivedObjectOfClasses:[NSSet setWithArray:@[[NSDictionary class], [NSArray class], [NSString class], [NSNumber class], [NSMutableSet class], [NSDate class], [Rule class]]]\n                                                       fromData:archivedRules error:&error];\n    if(nil == self.rules)\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: failed to unarchive rules from %{public}@ (%{public}@)\", RULES_FILE, error);\n        \n        //bail\n        goto bail;\n    }\n    \n    //make sure all item rules have a set for 'external' paths\n    // older rules didn't use this, so let's make do it here manually\n    for(NSString* key in self.rules)\n    {\n        //skip global rules\n        if(YES == [key isEqualToString:VALUE_ANY])\n        {\n            continue;\n        }\n        \n        //skip directory rules\n        // grab first/any rule and check\n        if(YES == ((Rule*)[self.rules[key][KEY_RULES] firstObject]).isDirectory.boolValue)\n        {\n            continue;\n        }\n        \n        //paths set nil?\n        // alloc for paths\n        if(nil == self.rules[key][KEY_PATHS])\n        {\n            //alloc\n            self.rules[key][KEY_PATHS] = [NSMutableSet set];\n        }\n    }\n    \n    //setup deletion for any rules that have an expiration\n    for(NSString* key in self.rules)\n    {\n        //item rules\n        itemRules = self.rules[key][KEY_RULES];\n        \n        //check each\n        for(Rule* rule in itemRules)\n        {\n            //skip\n            if(nil == rule.expiration)\n            {\n                continue;\n            }\n            \n            //dbg msg\n            os_log_debug(logHandle, \"loaded rule has an expiration date set: %{public}@\", rule.expiration);\n            \n            //interval\n            timeInterval = [rule.expiration timeIntervalSinceNow];\n            \n            //already expired?\n            // just go ahead and delete\n            if(timeInterval <= 0)\n            {\n                //delete\n                [self delete:rule.key rule:rule.uuid];\n            }\n            \n            //setup dispatch to delete\n            else\n            {\n                //dbg msg\n                os_log_debug(logHandle, \"setting up dispatch to delete one expiration is hit\");\n                \n                dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeInterval * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{\n                    \n                    //dbg msg\n                    os_log_debug(logHandle, \"rule expiration hit, will delete!\");\n                    \n                    //delete\n                    [self delete:rule.key rule:rule.uuid];\n                    \n                    //tell user rules changed\n                    [alerts.xpcUserClient rulesChanged];\n                    \n                });\n            }\n        }\n    }\n    \n    //dbg msg\n    os_log_debug(logHandle, \"loaded %lu rules\", (unsigned long)self.rules.count);\n    \n    //happy\n    result = YES;\n    \nbail:\n    \n    return result;\n}\n\n//generate default rules\n-(BOOL)generateDefaultRules\n{\n    //flag\n    BOOL generated = NO;\n    \n    //default binary\n    NSString* defaultBinary = nil;\n    \n    //(rule) info\n    NSMutableDictionary* info = nil;\n    \n    //binary\n    Binary* binary = nil;\n    \n    //set cs flags\n    SecCSFlags flags = kSecCSDefaultFlags | kSecCSCheckNestedCode | kSecCSDoNotValidateResources | kSecCSCheckAllArchitectures;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"generating default rules\");\n    \n    //iterate overall default rule paths\n    // generate binary obj/signing info for each\n    for(NSUInteger i=0; i<sizeof(DEFAULT_RULES)/sizeof(DEFAULT_RULES[0]); i++)\n    {\n        //extract binary\n        defaultBinary = DEFAULT_RULES[i];\n        \n        //dbg msg\n        os_log_debug(logHandle, \"processing (default) binary, %{public}@\", defaultBinary);\n        \n        //skip if binary doesn't exist\n        // some don't on newer versions of macOS\n        if(YES != [[NSFileManager defaultManager] fileExistsAtPath:defaultBinary]) continue;\n        \n        //init binary\n        binary = [[Binary alloc] init:DEFAULT_RULES[i]];\n        if(nil == binary)\n        {\n            //err msg\n            os_log_error(logHandle, \"ERROR: failed to generate binary for default rule: %{public}@\", DEFAULT_RULES[i]);\n            \n            //skip\n            continue;\n        }\n        \n        //generate signing info\n        [binary generateSigningInfo:flags];\n        \n        //alloc for (rule) info\n        info = [@{KEY_PATH:binary.path, KEY_ACTION:@RULE_STATE_ALLOW, KEY_TYPE:@RULE_TYPE_DEFAULT} mutableCopy];\n        \n        //add binary cs info\n        if(nil != binary.csInfo) info[KEY_CS_INFO] = binary.csInfo;\n        \n        //add\n        if(YES != [self add:[[Rule alloc] init:info] save:NO])\n        {\n            //err msg\n            os_log_error(logHandle, \"ERROR: failed to add rule\");\n            \n            //skip\n            continue;\n        }\n    }\n\n    //happy\n    generated = YES;\n    \nbail:\n    \n    return generated;\n}\n\n//add a (new) rule\n// and if specified, save to disk\n-(BOOL)add:(Rule*)rule save:(BOOL)save\n{\n    //result\n    BOOL added = NO;\n    \n    //interval for expirations\n    NSTimeInterval timeInterval = 0;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"adding rule: %{public}@ -> %{public}@\", rule.key, rule);\n\n    //sanity check\n    if(nil == rule)\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: can't add nil rule\");\n        \n        //bail\n        goto bail;\n    }\n    \n    //sync to access\n    @synchronized(self.rules)\n    {\n        //new rule for item\n        // need to init array for rules, paths, & cs info\n        if(nil == self.rules[rule.key])\n        {\n            //init\n            self.rules[rule.key] = [NSMutableDictionary dictionary];\n            \n            //init (proc) rules\n            self.rules[rule.key][KEY_RULES] = [NSMutableArray array];\n            \n            //add cs info\n            if(nil != rule.csInfo)\n            {\n                //add\n                self.rules[rule.key][KEY_CS_INFO] = rule.csInfo;\n            }\n            \n            //init set for all paths\n            self.rules[rule.key][KEY_PATHS] = [NSMutableSet set];\n        }\n        \n        //always add path (for UI)\n        // note, insertion into a set is unique\n        if(0 != rule.path.length)\n        {\n            //add\n            [self.rules[rule.key][KEY_PATHS] addObject:rule.path];\n        }\n        \n        //(now) add rule\n        [self.rules[rule.key][KEY_RULES] addObject:rule];\n\n    } //sync\n    \n    //handle expirations\n    // setup dispatch to delete once it hit\n    if(nil != rule.expiration)\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"rule has an expiration date set: %{public}@\", rule.expiration);\n        \n        timeInterval = [rule.expiration timeIntervalSinceNow];\n        if(timeInterval > 0) {\n            \n            //dbg msg\n            os_log_debug(logHandle, \"setting up dispatch to delete one expiration is hit\");\n            \n            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeInterval * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{\n                \n                //dbg msg\n                os_log_debug(logHandle, \"rule expiration hit, will delete!\");\n                \n                //delete\n                [self delete:rule.key rule:rule.uuid];\n                \n                //tell user rules changed\n                [alerts.xpcUserClient rulesChanged];\n                \n            });\n        }\n    }\n\n    //save\n    if(YES == save)\n    {\n        //save\n        if(YES != [self save])\n        {\n            //err msg\n            os_log_error(logHandle, \"ERROR: failed to save rules\");\n            \n            //bail\n            goto bail;\n        }\n        \n        //dbg msg\n        os_log_debug(logHandle, \"saved rule to disk\");\n    }\n    //no need to save\n    else\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"'save' not set (rule is temporary), so no need to write it out to disk\");\n    }\n    \n    //happy\n    added = YES;\n    \nbail:\n    \n    return added;\n}\n\n//update an item's cs info\n// and also the cs info of all its rule\n-(void)updateCSInfo:(Process*)process\n{\n    //dbg msg\n    os_log_debug(logHandle, \"updating code signing information for %{public}@ and its rules\", process);\n    \n    //sync\n    @synchronized(self.rules)\n    {\n        //update item's cs info\n        self.rules[process.key][KEY_CS_INFO] = process.csInfo;\n        \n        //update also the cs info of all its rule\n        for(Rule* rule in self.rules[process.key][KEY_RULES])\n        {\n            //update\n            rule.csInfo = process.csInfo;\n        }\n    }\n    \n    return;\n}\n\n//find (matching) rule\n-(Rule*)find:(Process*)process flow:(NEFilterSocketFlow*)flow csChange:(BOOL*)csChange\n{\n    //rule's cs info\n    NSDictionary* csInfo = nil;\n    \n    //matching rule\n    Rule* matchingRule = nil;\n    \n    //global rules\n    NSArray* globalRules = nil;\n    \n    //directory rules\n    NSMutableArray* directoryRules = nil;\n    \n    //item's rules\n    NSArray* itemRules = nil;\n    \n    //canidate rules\n    NSMutableArray* candidateRules = nil;\n    \n    //flag(s)\n    BOOL portAny = NO;\n    BOOL endpointAny = NO;\n    \n    //any match\n    // item has a '*:*' rule\n    Rule* anyMatch = nil;\n    \n    //partial match\n    // *:port or ip:*\n    Rule* partialMatch = nil;\n    \n    //exact match\n    Rule* exactMatch = nil;\n    \n    //remote endpoint\n    NWHostEndpoint* remoteEndpoint = nil;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"looking for rule for %{public}@ -> %{public}@\", process.key, process.path);\n    \n    //sync to access\n    @synchronized(self.rules)\n    {\n        //item rules\n        itemRules = self.rules[process.key][KEY_RULES];\n        \n        //extract cs info\n        csInfo = self.rules[process.key][KEY_CS_INFO];\n            \n        //cs info?\n        // make sure it (still) matches\n        if(nil != csInfo)\n        {\n            //mismatch?\n            // ignore...\n            if(YES != matchesCSInfo(process.csInfo, csInfo))\n            {\n                //set\n                *csChange = YES;\n                \n                //err msg\n                os_log_error(logHandle, \"ERROR: code signing mismatch: %{public}@ / %{public}@\", process.csInfo, csInfo);\n                \n                //bail\n                goto bail;\n            }\n        }\n       \n        //grab global rules\n        globalRules = self.rules[VALUE_ANY][KEY_RULES];\n        \n        //init directory rules\n        directoryRules = [NSMutableArray array];\n        \n        //add any directory rules\n        // i.e. any rule that's '/<anything>*'\n        for(NSString* key in self.rules)\n        {\n            //directory\n            NSString* directory = nil;\n            \n            //directory rule?\n            // grab first/any rule and check\n            if(YES == ((Rule*)[self.rules[key][KEY_RULES] firstObject]).isDirectory.boolValue)\n            {\n                //init directory\n                // ...by removing *\n                directory = [key substringToIndex:(key.length-1)];\n                \n                //does item fall within dir?\n                if(YES == [process.path hasPrefix:directory])\n                {\n                    //add\n                    [directoryRules addObjectsFromArray:self.rules[key][KEY_RULES]];\n                }\n            }\n        }\n        \n        //no global, directory, nor item rules\n        // bail, with no match so user is prompted\n        if( (nil == itemRules) &&\n            (nil == globalRules) &&\n            (0 == directoryRules.count) )\n        {\n            //no match\n            goto bail;\n        }\n        \n        //init candidate rules\n        candidateRules = [NSMutableArray array];\n        \n        //add global rules first\n        if(nil != globalRules) [candidateRules addObject:globalRules];\n        \n        //add directory rules next\n        if(0 != directoryRules.count) [candidateRules addObject:directoryRules];\n        \n        //add item's rules last...\n        if(nil != itemRules) [candidateRules addObject:itemRules];\n        \n        //extract remote endpoint\n        remoteEndpoint = (NWHostEndpoint*)flow.remoteEndpoint;\n        \n        //check each set of rules\n        // set: global, directory, and/or item rules\n        for(NSArray* rules in candidateRules)\n        {\n            //check all set of rules\n            // note: * is a wildcard, meaning any match\n            for(Rule* rule in rules)\n            {\n                //set flag: any port ('*')\n                portAny = [rule.endpointPort isEqualToString:VALUE_ANY];\n                \n                //set flag: any endpoint ('*', '0.0.0.0/0', or '::/0')\n                endpointAny = [self matchAnyEndpoint:rule flow:flow];\n                \n                //skip any disabled rule(s)\n                if(0 != rule.isDisabled.intValue) {\n                    \n                    //dbg msg\n                    os_log_debug(logHandle, \"skipping disabled rule match %{public}@\", rule);\n                    \n                    //skip\n                    continue;\n                }\n                \n                //checks for temp rules\n                if(YES == [rule isTemporary])\n                {\n                    //process?\n                    // check process's pid matches rule's pid\n                    if( (nil != rule.pid) &&\n                        (rule.pid.unsignedIntValue != process.pid) )\n                    {\n                        //skip\n                        continue;\n                    }\n                }\n                \n                //expiration?\n                // double check if 'now' is after expiration\n                if( (nil != rule.expiration) &&\n                    ([[NSDate date] compare:rule.expiration] == NSOrderedDescending) )\n                {\n                    //err msg\n                    os_log_error(logHandle, \"ERROR: rule %{public}@ has expired, should already have been removed\", rule);\n                    \n                    //skip\n                    continue;\n                }\n                \n                //match on any (addr) and any (port)\n                if( (YES == portAny) &&\n                    (YES == endpointAny) )\n                {\n                    //dbg msg\n                    os_log_debug(logHandle, \"rule match: 'any' address and port\");\n                    \n                    //any\n                    anyMatch = rule;\n                    \n                    //next\n                    continue;\n                }\n                \n                //port is any?\n                // check for (partial) rule match: endpoint addr\n                else if(YES == portAny)\n                {\n                    //dbg msg\n                    os_log_debug(logHandle, \"rule port is any ('*'), will check host/url\");\n                    \n                    //check endpoint host/url\n                    if(YES == [self endpointAddrMatch:flow rule:rule])\n                    {\n                        //dbg msg\n                        os_log_debug(logHandle, \"rule match: 'partial' (addr)\");\n                        \n                        //partial\n                        partialMatch = rule;\n                        \n                        //next\n                        continue;\n                    }\n                }\n                \n                //endpoint addr is any?\n                // check for (partial) rule match: endpoint port\n                else if(YES == endpointAny)\n                {\n                    //dbg msg\n                    os_log_debug(logHandle, \"rule address is any ('*', '0.0.0.0/0', or '::/0'), will check port\");\n                    \n                    //addr is any\n                    //so check the port\n                    if(YES == [rule.endpointPort isEqualToString:remoteEndpoint.port])\n                    {\n                        //dbg msg\n                        os_log_debug(logHandle, \"rule match: 'partial' (port)\");\n                        \n                        //partial\n                        partialMatch = rule;\n                        \n                        //next\n                        continue;\n                    }\n                }\n                \n                //addr and port both set (not '*')\n                // check that both endpoint addr and port match\n                else\n                {\n                    //dbg msg\n                    os_log_debug(logHandle, \"address and port set (%{public}@:%{public}@), will check both for match\", rule.endpointAddr, rule.endpointPort);\n                    \n                    //match?\n                    if( (YES == [self endpointAddrMatch:flow rule:rule]) &&\n                        (YES == [rule.endpointPort isEqualToString:remoteEndpoint.port]) )\n                    {\n                        //dbg msg\n                        os_log_debug(logHandle, \"rule match: 'exact' address and port\");\n                            \n                        //exact\n                        exactMatch = rule;\n                        \n                        //next\n                        continue;\n                    }\n                }\n                    \n            } //all rule set\n        \n        } //all candidate rules\n        \n        //extact match?\n        if(nil != exactMatch) matchingRule = exactMatch;\n        \n        //partial match?\n        else if (nil != partialMatch) matchingRule = partialMatch;\n        \n        //any match?\n        else if (nil != anyMatch) matchingRule = anyMatch;\n    \n    }//sync\n        \nbail:\n    \n    return matchingRule;\n}\n\n//check if endpoint addr matches \"any\"\n// either '*' or (IPv4) '0.0.0.0/0' or (IPv6) '::/0'\n-(BOOL)matchAnyEndpoint:(Rule*)rule flow:(NEFilterSocketFlow*)flow\n{\n    //flag\n    BOOL matchesAny = NO;\n    \n    //first check any '*'\n    if([rule.endpointAddr isEqualToString:VALUE_ANY])\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"rule match: 'any' ('*')\");\n        \n        matchesAny = YES;\n        goto bail;\n    }\n    \n    //check for IPV4 -> '0.0.0.0/0'\n    if( (AF_INET == flow.socketFamily) &&\n        ([rule.endpointAddr isEqualToString:@\"0.0.0.0/0\"]) )\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"rule match: 'any' (IPv4: '0.0.0.0/0')\");\n        \n        matchesAny = YES;\n        goto bail;\n    }\n    //check for IPV6 -> '::/0'\n    if( (AF_INET6 == flow.socketFamily) &&\n        ([rule.endpointAddr isEqualToString:@\"::/0\"]) )\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"rule match: 'any' (IPv6: '::/0')\");\n        \n        matchesAny = YES;\n        goto bail;\n\n    }\n    \nbail:\n    \n    return matchesAny;\n}\n\n//check if endpoint host or url matches\n// extra logic for checking/applying regex, etc...\n-(BOOL)endpointAddrMatch:(NEFilterSocketFlow*)flow rule:(Rule*)rule\n{\n    //match\n    BOOL isMatch = NO;\n    \n    //error\n    NSError* error = nil;\n    \n    //endpoint url/hosts\n    NSMutableArray* endpointNames = nil;\n    \n    //endpoint regex\n    NSRegularExpression* endpointAddrRegex = nil;\n    \n    //remote endpoint\n    NWHostEndpoint* remoteEndpoint = nil;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"%s\", __PRETTY_FUNCTION__);\n    \n    //extract remote endpoint\n    remoteEndpoint = (NWHostEndpoint*)flow.remoteEndpoint;\n    \n    //init endpoint names\n    endpointNames = [NSMutableArray array];\n    \n    //add url\n    // and just host (as this is what is shown in alert)\n    if(nil != flow.URL.absoluteString)\n    {\n        //add full url\n        [endpointNames addObject:flow.URL.absoluteString];\n        \n        //add host\n        [endpointNames addObject:flow.URL.host];\n    }\n    \n    //add host name\n    if(nil != remoteEndpoint.hostname)\n    {\n        //add\n        [endpointNames addObject:remoteEndpoint.hostname];\n    }\n    \n    //macOS 11+?\n    // add remote host name\n    if(@available(macOS 11, *))\n    {\n        //add remote host name\n        if(nil != flow.remoteHostname)\n        {\n            //add\n            [endpointNames addObject:flow.remoteHostname];\n        }\n    }\n    \n    //dbg msg\n    os_log_debug(logHandle, \"checking rule's endpoint address (%{public}@) and rule's endpoint host %{public}@ against %{public}@\", rule.endpointAddr, rule.endpointHost, endpointNames);\n    \n    //endpoint addr a regex?\n    // init regex and check for match\n    if(YES == rule.isEndpointAddrRegex)\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"rule's endpoint address is a regex...\");\n        \n        //init regex\n        endpointAddrRegex = [NSRegularExpression regularExpressionWithPattern:rule.endpointAddr options:0 error:&error];\n        if(nil == endpointAddrRegex)\n        {\n            //err msg\n            os_log_error(logHandle, \"ERROR: failed to created regex from %{public}@ (error: %{public}@)\", rule.endpointAddr, error);\n            \n            //bail\n            goto bail;\n        }\n        \n        //check each\n        for(NSString* endpointName in endpointNames)\n        {\n            //match?\n            if(0 != [endpointAddrRegex numberOfMatchesInString:endpointName options:0 range:NSMakeRange(0, endpointName.length)])\n            {\n                //dbg msg\n                os_log_debug(logHandle, \"rule match: regex on %{public}@\", endpointName);\n                \n                //match\n                isMatch = YES;\n                \n                //bail\n                goto bail;\n            }\n        }\n    }\n    \n    //not regex\n    // check rule's endpoint address and host for (exact) match\n    else\n    {\n        //check each\n        for(NSString* endpointName in endpointNames)\n        {\n            //dbg msg\n            os_log_debug(logHandle, \"checking %{public}@ vs. %{public}@\", rule.endpointAddr, endpointName);\n            \n            //check against rule's endpoint address\n            if(NSOrderedSame == [rule.endpointAddr caseInsensitiveCompare:endpointName])\n            {\n                //dbg msg\n                os_log_debug(logHandle, \"rule match (endpoint address): %{public}@\", endpointName);\n                \n                //match\n                isMatch = YES;\n                goto bail;\n            }\n            \n            //(also) check against rule's endpoint host\n            if( (nil != rule.endpointHost) &&\n                (NSOrderedSame == [rule.endpointHost caseInsensitiveCompare:endpointName]) )\n            {\n                //dbg msg\n                os_log_debug(logHandle, \"rule match: (endpoint host) %{public}@\", endpointName);\n                \n                //match\n                isMatch = YES;\n                goto bail;\n            }\n        }\n    }\n    \nbail:\n        \n    return isMatch;\n}\n\n//toggle rule\n// either disable, or (re)enable\n-(BOOL)toggleRule:(NSString*)key rule:(NSString*)uuid state:(NSNumber*)state\n{\n    //result\n    BOOL result = NO;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"toggling rule, key: %{public}@, rule id: %{public}@\", key, uuid);\n    \n    //sync to access\n    @synchronized(self.rules)\n    {\n        //no uuid\n        // set all (process') rules to specified state\n        if(nil == uuid)\n        {\n            //toggle all\n            for(Rule* rule in self.rules[key][KEY_RULES])\n            {\n                //enable\n                if(RULE_TOGGLE_STATE_ENABLE == state.intValue) {\n                    rule.isDisabled = nil;\n                }\n                //disable\n                else\n                {\n                    rule.isDisabled = @YES;\n                }\n            }\n            \n            //happy\n            result = YES;\n            \n            //done\n            goto bail;\n        }\n        \n        //find matching rule\n        [self.rules[key][KEY_RULES] enumerateObjectsUsingBlock:^(Rule* currentRule, NSUInteger index, BOOL* stop)\n        {\n            //is match?\n            if(YES == [currentRule.uuid isEqualToString:uuid])\n            {\n                //enable\n                if(RULE_TOGGLE_STATE_ENABLE == state.intValue) {\n                    currentRule.isDisabled = nil;\n                }\n                //disable\n                else\n                {\n                    currentRule.isDisabled = @YES;\n                }\n                \n                //done\n                *stop = YES;\n            }\n        }];\n        \n    } //sync\n        \n    //happy\n    result = YES;\n    \nbail:\n    \n    //always save to disk\n    if(YES != [self save])\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: failed to save (toggled) rules\");\n        \n        //not happy\n        result = NO;\n    }\n    \n    return result;\n}\n\n//delete rule\n-(BOOL)delete:(NSString*)key rule:(NSString*)uuid\n{\n    //result\n    BOOL result = NO;\n    \n    //rule index\n    __block NSUInteger ruleIndex = -1;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"deleting rule, key: %{public}@, rule id: %{public}@\", key, uuid);\n    \n    //sync to access\n    @synchronized(self.rules)\n    {\n        //no uuid\n        // delete all (process') rules\n        if(nil == uuid)\n        {\n            //remove\n            [self.rules removeObjectForKey:key];\n            \n            //happy\n            result = YES;\n            \n            //done\n            goto bail;\n        }\n        \n        //find matching rule\n        [self.rules[key][KEY_RULES] enumerateObjectsUsingBlock:^(Rule* currentRule, NSUInteger index, BOOL* stop)\n        {\n            //is match?\n            if(YES == [currentRule.uuid isEqualToString:uuid])\n            {\n                //save index\n                ruleIndex = index;\n            \n                //stop\n                *stop = YES;\n            }\n        }];\n        \n        //dbg msg\n        os_log_debug(logHandle, \"found rule at index: %lu\", (unsigned long)ruleIndex);\n        \n        //remove\n        if(-1 != ruleIndex)\n        {\n            //remove\n            [self.rules[key][KEY_RULES] removeObjectAtIndex:ruleIndex];\n            \n            //last (item) rule?\n            if(0 == ((NSMutableArray*)self.rules[key][KEY_RULES]).count)\n            {\n                //dbg msg\n                os_log_debug(logHandle, \"rule was only/last one for %{public}@, so removing item entry\", key);\n                \n                //remove process\n                [self.rules removeObjectForKey:key];\n            }\n        }\n        \n    } //sync\n        \n    //happy\n    result = YES;\n    \nbail:\n    \n    //always save to disk\n    if(YES != [self save])\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: failed to save (updated) rules\");\n        \n        //not happy\n        result = NO;\n    }\n    \n    return result;\n}\n\n//save to disk\n// note: temporary rules are ignored\n-(BOOL)save\n{\n    //result\n    BOOL result = NO;\n    \n    //error\n    NSError* error = nil;\n    \n    //rule's file\n    NSString* rulesFile = nil;\n    \n    //persistent rules\n    NSMutableDictionary* persistentRules = nil;\n    \n    //archived rules\n    NSData* archivedRules = nil;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"method '%s' invoked\", __PRETTY_FUNCTION__);\n    \n    //init\n    persistentRules = [NSMutableDictionary dictionary];\n    \n    //init path\n    rulesFile = [self getPath];\n    \n    //dbg msg\n    os_log_debug(logHandle, \"saving (non-temp) rules to %{public}@\", rulesFile);\n    \n    //sync to save\n    @synchronized(self) {\n        \n        //generate list of non-temp rules\n        // these are the ones we'll write out\n        for(NSString* key in self.rules.allKeys)\n        {\n            //item's rules\n            NSMutableArray* itemRules = nil;\n            \n            //init\n            itemRules = [NSMutableArray array];\n            \n            //add only non-temporary rules\n            for(Rule* itemRule in self.rules[key][KEY_RULES])\n            {\n                //temp?\n                if(YES == [itemRule isTemporary])\n                {\n                    //skip\n                    continue;\n                }\n                \n                //add\n                [itemRules addObject:itemRule];\n            }\n            \n            //any non-temp rules?\n            // add to rules we're going to write out\n            if(0 != itemRules.count)\n            {\n                //start w/ empty dictionary\n                persistentRules[key] = [NSMutableDictionary dictionary];\n                                \n                //add (non-temp) rules\n                persistentRules[key][KEY_RULES] = itemRules;\n                \n                //add cs info\n                if(nil != self.rules[key][KEY_CS_INFO])\n                {\n                    //add\n                    persistentRules[key][KEY_CS_INFO] = self.rules[key][KEY_CS_INFO];\n                }\n                \n                //add paths info\n                if(nil != self.rules[key][KEY_PATHS])\n                {\n                    //add\n                    persistentRules[key][KEY_PATHS] = self.rules[key][KEY_PATHS];\n                }\n            }\n        }\n        \n        //serialize\n        archivedRules = [NSKeyedArchiver archivedDataWithRootObject:persistentRules requiringSecureCoding:YES error:&error];\n        if(nil == archivedRules)\n        {\n            //err msg\n            os_log_error(logHandle, \"ERROR: failed to serialize rules: %{public}@\", error);\n                \n            //bail\n            goto bail;\n        }\n        \n        //dbg msg\n        os_log_debug(logHandle, \"serialized rules\");\n        \n        //write out rules\n        if(YES != [archivedRules writeToFile:rulesFile atomically:YES])\n        {\n            //err msg\n            os_log_error(logHandle, \"ERROR: failed to save archived rules to: %{public}@\", rulesFile);\n            \n            //bail\n            goto bail;\n        }\n        \n    } //sync\n    \n    //happy\n    result = YES;\n    \nbail:\n    \n    return result;\n}\n\n//import rules\n-(BOOL)import:(NSData*)importedRules userOnly:(BOOL)userOnly\n{\n    //flag\n    BOOL result = NO;\n    \n    //unserialized rules\n    NSDictionary* unarchivedRules = nil;\n    \n    //error\n    NSError* error = nil;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"method '%s' invoked with %{public}@\", __PRETTY_FUNCTION__, importedRules);\n    \n    //sanity check\n    if(YES != [importedRules isKindOfClass:[NSData class]])\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: imported rules are not a NSData\");\n        goto bail;\n    }\n        \n    //unarchive\n    unarchivedRules = [NSKeyedUnarchiver unarchivedObjectOfClasses:[NSSet setWithArray:@[[NSDictionary class], [NSArray class], [NSString class], [NSNumber class], [NSMutableSet class], [NSDate class], [Rule class]]] fromData:importedRules error:&error];\n    \n    //error?\n    if( (nil != error) ||\n        (nil == unarchivedRules) )\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: failed to unarchive (imported) rules (error: %{public}@)\", error);\n        goto bail;\n    }\n    \n    //dbg msg\n    os_log_debug(logHandle, \"unarchived (imported) %lu rules\", (unsigned long)unarchivedRules.count);\n    \n    //update\n    @synchronized (self)\n    {\n        //full update\n        if(!userOnly) {\n            \n            //dbg msg\n            os_log_debug(logHandle, \"full import\");\n            \n            //update all\n            self.rules = [unarchivedRules mutableCopy];\n        }\n        //user-only update\n        else\n        {\n            //dbg msg\n            os_log_debug(logHandle, \"partial (user-created only) import\");\n            \n            //first: remove all existing user-created rules\n            for(NSString* key in self.rules.allKeys) {\n                \n                //get rules for key\n                NSMutableArray* existingRules = self.rules[key][KEY_RULES];\n                \n                //remove user-created rules\n                [existingRules filterUsingPredicate:\n                    [NSPredicate predicateWithBlock:^BOOL(Rule* rule, NSDictionary* bindings) {\n                        return (rule.type.intValue != RULE_TYPE_USER);\n                    }]\n                ];\n                \n                //no rules left?\n                // remove entire key\n                if(0 == existingRules.count) {\n                    [self.rules removeObjectForKey:key];\n                }\n            }\n            \n            //second: merge in imported user rules\n            for(NSString* key in unarchivedRules) {\n                \n                //key exists?\n                // (has non-user rules)\n                if(nil != self.rules[key]){\n                    //append imported rules\n                    [self.rules[key][KEY_RULES] addObjectsFromArray:unarchivedRules[key][KEY_RULES]];\n                }\n                //new key\n                else{\n                    //add entire entry\n                    self.rules[key] = [unarchivedRules[key] mutableCopy];\n                }\n            }\n        }\n    }\n    \n    //save\n    if(YES != [self save])\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: failed to save (imported) rules\");\n        \n        //bail\n        goto bail;\n    }\n    \n    //dbg msg\n    os_log_debug(logHandle, \"saved (imported) rules\");\n    \n    //happy\n    result = YES;\n    \nbail:\n    \n    return result;\n}\n\n//cleanup\n// a) rule expired\n// a) path was deleted\n// b) point to non-existent processes (temp rule)\n-(NSUInteger)cleanup:(BOOL)full\n{\n    //count\n    NSUInteger deletedRules = 0;\n    \n    //rules to delete\n    NSMutableArray* rules2Delete = nil;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"cleaning up rules (full?: %d)\", full);\n    \n    //alloc\n    rules2Delete = [NSMutableArray array];\n    \n    //sync to access\n    @synchronized(self.rules)\n    {\n        //gather all rules\n        for(NSString* key in self.rules.allKeys)\n        {\n            //paths\n            NSArray* paths = nil;\n            \n            //path\n            NSString* path = nil;\n            \n            //rules for item\n            NSArray* rules = nil;\n            \n            //(first) rule\n            Rule* rule = nil;\n            \n            //flag\n            BOOL allDeleted = YES;\n            \n            //interval for expiration check\n            NSTimeInterval timeInterval = 0;\n            \n            //extract 'external' paths\n            paths = self.rules[key][KEY_PATHS];\n            \n            //extract rules for item\n            rules = self.rules[key][KEY_RULES];\n            \n            //extract (first) rule\n            rule = rules.firstObject;\n            \n            //skip global rules\n            if(YES == rule.isGlobal.boolValue)\n            {\n                //skip\n                continue;\n            }\n            \n            //only do path checks on full cleanup\n            if(full)\n            {\n                //directory rule?\n                // check if directory has been deleted\n                if(YES == rule.isDirectory.boolValue)\n                {\n                    //directory rules end in /*\n                    // so first remove the trailing '*'\n                    path = [rule.path substringToIndex:rule.path.length - 1];\n                    \n                    //was directory deleted?\n                    if(YES != [NSFileManager.defaultManager fileExistsAtPath:path])\n                    {\n                        //dbg msg\n                        os_log_debug(logHandle, \"%{public}@ is gone, will delete directory rule\", path);\n                        \n                        //add to list\n                        [rules2Delete addObject:rule];\n                    }\n                    \n                    //next\n                    continue;\n                }\n                \n                //for (normal) item rules\n                // first set flag if all 'external' paths have been deleted\n                for(NSString* path in paths)\n                {\n                    //path still there?\n                    if(YES == [NSFileManager.defaultManager fileExistsAtPath:path])\n                    {\n                        //toggle\n                        allDeleted = NO;\n                        \n                        //done\n                        break;\n                    }\n                }\n            }\n            \n            //check each rule's 'internal' path\n            // and expiration, and process id (temp rules)\n            for(Rule* rule in rules)\n            {\n                //only do path checks on full cleanup\n                if(full)\n                {\n                    //was path deleted?\n                    // and all 'external' paths too?\n                    if( (YES == allDeleted) &&\n                       (YES != [NSFileManager.defaultManager fileExistsAtPath:rule.path]))\n                    {\n                        //dbg msg\n                        os_log_debug(logHandle, \"%{public}@ is gone - will delete rule\", rule.path);\n                        \n                        //add to list\n                        [rules2Delete addObject:rule];\n                        \n                        //next\n                        continue;\n                    }\n                }\n                \n                //did process (for temp rule) exit?\n                if( (YES == [rule isTemporary]) &&\n                    (YES != isAlive(rule.pid.intValue)) )\n                {\n                    //dbg msg\n                    os_log_debug(logHandle, \"process-level (temporary) rule's process (%@) has exited - will delete rule\", rule.pid);\n                    \n                    //add to list\n                    [rules2Delete addObject:rule];\n                    \n                    //next\n                    continue;\n                }\n                \n                //did rule expire?\n                if(nil != rule.expiration)\n                {\n                    //compute interval\n                    // and check if it expired\n                    timeInterval = [rule.expiration timeIntervalSinceNow];\n                    if(timeInterval <= 0)\n                    {\n                        //dbg msg\n                        os_log_debug(logHandle, \"rule's expiration has hit (%@) - will delete rule\", rule.expiration);\n                        \n                        //add to list\n                        [rules2Delete addObject:rule];\n                        \n                        //next\n                        continue;\n                    }\n                }\n            }\n        }\n    }\n    \n    //save count\n    deletedRules = rules2Delete.count;\n    \n    //now delete each\n    for(Rule* rule in rules2Delete)\n    {\n        //delete\n        [self delete:rule.key rule:rule.uuid];\n    }\n    \n    //dbg msg\n    os_log_debug(logHandle, \"cleaned up/deleted %ld rules\", (long)deletedRules);\n    \n    return deletedRules;\n}\n\n@end\n"
  },
  {
    "path": "LuLu/Extension/XPCDaemon.h",
    "content": "//\n//  file: XPCDaemon.h\n//  project: lulu (launch daemon)\n//  description: interface for XPC methods, invoked by user (header)\n//\n//  created by Patrick Wardle\n//  copyright (c) 2017 Objective-See. All rights reserved.\n//\n\n@import OSLog;\n@import Foundation;\n\n#import \"XPCDaemonProto.h\"\n\n@interface XPCDaemon : NSObject <XPCDaemonProtocol>\n{\n    \n}\n\n/* PROPERTIES */\n\n@end\n"
  },
  {
    "path": "LuLu/Extension/XPCDaemon.m",
    "content": "//\n//  file: XPCDaemon.m\n//  project: lulu (launch daemon)\n//  description: interface for XPC methods, invoked by user\n//\n//  created by Patrick Wardle\n//  copyright (c) 2017 Objective-See. All rights reserved.\n//\n\n#import \"Rule.h\"\n#import \"Rules.h\"\n#import \"Alerts.h\"\n#import \"consts.h\"\n#import \"Profiles.h\"\n#import \"XPCDaemon.h\"\n#import \"utilities.h\"\n#import \"Preferences.h\"\n\n//global rules obj\nextern Rules* rules;\n\n//global alerts obj\nextern Alerts* alerts;\n\n//global profiles obj\nextern Profiles* profiles;\n\n//global prefs obj\nextern Preferences* preferences;\n\n//global log handle\nextern os_log_t logHandle;\n\n@implementation XPCDaemon\n\n//send preferences to the client\n-(void)getPreferences:(void (^)(NSDictionary*))reply\n{\n    //dbg msg\n    os_log_debug(logHandle, \"XPC request: '%s'\", __PRETTY_FUNCTION__);\n    \n    //reply w/ prefs\n    reply(preferences.preferences);\n        \n    return;\n}\n\n//update preferences\n// note: sends full preferences back to the client\n-(void)updatePreferences:(NSDictionary*)updates reply:(void (^)(NSDictionary*))reply\n{\n    //dbg msg\n    os_log_debug(logHandle, \"XPC request: '%s' (%{public}@)\", __PRETTY_FUNCTION__, updates);\n    \n    //call into prefs obj\n    if(YES != [preferences update:updates replace:NO])\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: failed to updates to preferences\");\n    }\n    \n    //reply w/ prefs\n    reply(preferences.preferences);\n    \n    return;\n}\n\n//send rules to the client\n-(void)getRules:(void (^)(NSData*))reply\n{\n    //archived rules\n    NSData* archivedRules = nil;\n    \n    //error\n    NSError* error = nil;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"XPC request: '%s'\", __PRETTY_FUNCTION__);\n    \n    //archive rules\n    archivedRules = [NSKeyedArchiver archivedDataWithRootObject:rules.rules requiringSecureCoding:YES error:&error];\n    if(nil == archivedRules)\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: failed to archive rules: %{public}@\", error);\n            \n    } else os_log_debug(logHandle, \"archived %lu rules, and sending to user...\", (unsigned long)rules.rules.count);\n\n    //reply w/ rules\n    reply(archivedRules);\n           \n    return;\n}\n\n//add a rule\n-(void)addRule:(NSDictionary*)info\n{\n    //binary obj\n    Binary* binary = nil;\n    \n    //rule info\n    NSMutableDictionary* ruleInfo = nil;\n    \n    //default cs flags\n    SecCSFlags flags = kSecCSDefaultFlags | kSecCSCheckNestedCode | kSecCSDoNotValidateResources | kSecCSCheckAllArchitectures;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"XPC request: '%s' with info: %{public}@\", __PRETTY_FUNCTION__, info);\n    \n    //make copy\n    ruleInfo = [info mutableCopy];\n    \n    //non-specific path\n    // init binary and cs info\n    if(YES != [info[KEY_PATH] hasSuffix:VALUE_ANY])\n    {\n        //init binary obj w/ path\n        binary = [[Binary alloc] init:info[KEY_PATH]];\n        if(nil == binary)\n        {\n            //err msg\n            os_log_error(logHandle, \"ERROR: failed init binary object for %@\", info[KEY_PATH]);\n            \n            //bail\n            goto bail;\n        }\n        \n        //generate cs info\n        [binary generateSigningInfo:flags];\n        \n        //add any code signing info\n        if(nil != binary.csInfo) \n        {\n            //add\n            ruleInfo[KEY_CS_INFO] = binary.csInfo;\n        }\n    }\n    \n    //create and add rule\n    if(YES != [rules add:[[Rule alloc] init:ruleInfo] save:YES])\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: failed to add rule for %{public}@\", ruleInfo[KEY_PATH]);\n         \n        //bail\n        goto bail;\n    }\n    \n    //dbg msg\n    os_log_debug(logHandle, \"added rule\");\n    \nbail:\n    \n    return;\n}\n\n//disable (or re-enable) rule\n-(void)toggleRule:(NSString*)key rule:(NSString*)uuid state:(NSNumber*)state\n{\n    //dbg msg\n    os_log_debug(logHandle, \"XPC request: '%s' with key: %{public}@, rule id: %{public}@\", __PRETTY_FUNCTION__, key, uuid);\n    \n    //toggle\n    if(YES != [rules toggleRule:key rule:uuid state:state])\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: failed to toggle rule\");\n        \n        //bail\n        goto bail;\n    }\n    \n    //dbg msg\n    os_log_debug(logHandle, \"toggled rule\");\n    \nbail:\n    \n    return;\n\n}\n\n//delete rule\n-(void)deleteRule:(NSString*)key rule:(NSString*)uuid\n{\n    //dbg msg\n    os_log_debug(logHandle, \"XPC request: '%s' with key: %{public}@, rule id: %{public}@\", __PRETTY_FUNCTION__, key, uuid);\n\n    //delete rule\n    if(YES != [rules delete:key rule:uuid])\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: failed to delete rule\");\n        \n        //bail\n        goto bail;\n    }\n    \n    //dbg msg\n    os_log_debug(logHandle, \"deleted rule\");\n    \nbail:\n    \n    return;\n}\n\n//import rules\n-(void)importRules:(NSData*)importedRules userOnly:(BOOL)userOnly result:(void (^)(BOOL))reply\n{\n    //dbg msg\n    os_log_debug(logHandle, \"XPC request: '%s'\", __PRETTY_FUNCTION__);\n    \n    //import rules\n    reply([rules import:importedRules userOnly:userOnly]);\n\n    return;\n}\n\n//cleanup rules\n-(void)cleanupRules:(BOOL)full reply:(void (^)(NSInteger))reply\n{\n    //dbg msg\n    os_log_debug(logHandle, \"XPC request: '%s'\", __PRETTY_FUNCTION__);\n    \n    //cleanup rules\n    reply([rules cleanup:full]);\n\n    return;\n}\n\n//uninstall\n-(void)uninstall:(void (^)(BOOL))reply\n{\n    //flag\n    BOOL uninstalled = NO;\n    \n    //directory\n    NSString* path = nil;\n\n    //error\n    NSError* error = nil;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"XPC request: '%s'\", __PRETTY_FUNCTION__);\n    \n    //init path w/ install dir\n    path = INSTALL_DIRECTORY;\n    \n    //remove install directory\n    if(YES != [NSFileManager.defaultManager removeItemAtPath:path error:&error])\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: failed to remove %{public}@ (error: %{public}@)\", path, error);\n    }\n    else\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"removed %{public}@\", path);\n        \n        //happy\n        uninstalled = YES;\n    }\n    \n    //up to Obj-See's install dir\n    path = [path stringByDeletingLastPathComponent];\n    \n    //no other Obj-See tools?\n    // remove the Obj-See directory too\n    if( (0 == [[NSFileManager.defaultManager contentsOfDirectoryAtPath:path error:&error] count]) &&\n        (nil == error) )\n    {\n        //remove\n        if(YES != [NSFileManager.defaultManager removeItemAtPath:path error:&error])\n        {\n            //err msg\n            os_log_error(logHandle, \"ERROR: failed to delete %{public}@ (error: %{public}@)\", path, error);\n        }\n        else\n        {\n            //dbg msg\n            os_log_debug(logHandle, \"removed %{public}@\", path);\n            \n            //happy\n            uninstalled = YES;\n        }\n    }\n    \n    //return result\n    reply(uninstalled);\n    \n    return;\n}\n\n//get current profile *name*\n-(void)getCurrentProfile:(void (^)(NSString*))reply\n{\n    //dbg msg\n    os_log_debug(logHandle, \"XPC request: '%s'\", __PRETTY_FUNCTION__);\n    \n    //reply\n    reply([[preferences getCurrentProfile] lastPathComponent]);\n        \n    return;\n}\n\n//get list of profile names\n-(void)getProfiles:(void (^)(NSArray*))reply\n{\n    //dbg msg\n    os_log_debug(logHandle, \"XPC request: '%s'\", __PRETTY_FUNCTION__);\n    \n    //reply w/ prefs\n    // return immutable copy\n    reply([profiles enumerate].copy);\n        \n    return;\n}\n\n//add profile\n-(void)addProfile:(NSString*)name preferences:(NSDictionary*)preferences reply:(void (^)(BOOL))reply\n{\n    //flag\n    BOOL wasAdded = NO;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"XPC request: '%s' with %{public}@\", __PRETTY_FUNCTION__, name);\n    \n    //create and add profile\n    if(YES != [profiles add:name preferences:preferences])\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: failed to add new profile '%{public}@'\", name);\n         \n        //bail\n        goto bail;\n    }\n    \n    //happy\n    wasAdded = YES;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"added new profile '%{public}@'\", name);\n    \nbail:\n    \n    reply(wasAdded);\n    \n    return;\n}\n\n//set profile\n-(void)setProfile:(NSString*)name reply:(void (^)(BOOL))reply\n{\n    //flag\n    BOOL wasSet = NO;\n    \n    //full path\n    NSString* newProfilePath = nil;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"XPC request: '%s' with name: %{public}@\", __PRETTY_FUNCTION__, name);\n\n    //new profile?\n    if(nil != name)\n    {\n        //init path for new profile directory\n        newProfilePath = [profiles.directory stringByAppendingPathComponent:name];\n    }\n    \n    //set\n    [profiles set:newProfilePath];\n    \n    //reload rules\n    [rules load];\n    \n    //tell user rules changed\n    // ...in case rule's window need refreshing\n    [alerts.xpcUserClient rulesChanged];\n    \n    //reload prefs\n    [preferences load];\n    \n    //happy\n    wasSet = YES;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"set profile to %{public}@\", newProfilePath ? newProfilePath : @\"Default\");\n    \n    reply(wasSet);\n    \n    return;\n}\n\n//delete profile\n-(void)deleteProfile:(NSString*)name reply:(void (^)(BOOL))reply\n{\n    //flag\n    BOOL wasDeleted = NO;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"XPC request: '%s' with name: %{public}@\", __PRETTY_FUNCTION__, name);\n    \n    //sanity check\n    if(nil == name)\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: profile name is nil, so ignoring...\");\n        goto bail;\n    }\n\n    //delete profile\n    if(YES != [profiles delete:name])\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: failed to delete profile\");\n        goto bail;\n    }\n    \n    //happy\n    wasDeleted = YES;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"deleted profile %{public}@\", name);\n    \nbail:\n    \n    reply(wasDeleted);\n    \n    return;\n}\n\n@end\n"
  },
  {
    "path": "LuLu/Extension/XPCListener.h",
    "content": "//\n//  file: XPCListener\n//  project: lulu (launch daemon)\n//  description: XPC listener for connections for user components (header)\n//\n//  created by Patrick Wardle\n//  copyright (c) 2017 Objective-See. All rights reserved.\n//\n\n\n@import OSLog;\n@import Foundation;\n\n#import \"XPCDaemonProto.h\"\n\n//function def\nOSStatus SecTaskValidateForRequirement(SecTaskRef task, CFStringRef requirement);\n\n@interface XPCListener : NSObject <NSXPCListenerDelegate>\n{\n    \n}\n\n/* PROPERTIES */\n\n//XPC listener\n@property(nonatomic, retain)NSXPCListener* listener;\n\n//XPC connection for login item\n@property(weak)NSXPCConnection* client;\n\n@end\n"
  },
  {
    "path": "LuLu/Extension/XPCListener.m",
    "content": "//\n//  file: XPCListener.m\n//  project: lulu (launch daemon)\n//  description: XPC listener for connections for user components\n//\n//  created by Patrick Wardle\n//  copyright (c) 2017 Objective-See. All rights reserved.\n//\n\n#import \"consts.h\"\n\n#import \"Rule.h\"\n#import \"Rules.h\"\n#import \"Alerts.h\"\n#import \"utilities.h\"\n#import \"XPCListener.h\"\n\n#import \"XPCDaemon.h\"\n\n#import \"XPCUserProto.h\"\n#import \"XPCDaemonProto.h\"\n\n@import OSLog;\n#import <bsm/libbsm.h>\n\n\n/* GLOBALS */\n\n//alerts\nextern Alerts* alerts;\n\n//interface for 'extension' to NSXPCConnection\n// allows us to access the 'private' auditToken iVar\n@interface ExtendedNSXPCConnection : NSXPCConnection\n{\n    //private iVar\n    audit_token_t auditToken;\n}\n//private iVar\n@property audit_token_t auditToken;\n\n@end\n\n//implementation for 'extension' to NSXPCConnection\n// allows us to access the 'private' auditToken iVar\n@implementation ExtendedNSXPCConnection\n\n//private iVar\n@synthesize auditToken;\n\n@end\n\n//global logging handle\nextern os_log_t logHandle;\n\n@implementation XPCListener\n\n@synthesize client;\n@synthesize listener;\n\n//init\n// create XPC listener\n-(id)init\n{\n    //code signing requirement\n    NSString* requirement = nil;\n    \n    //init super\n    self = [super init];\n    if(nil != self)\n    {\n        //init listener\n        listener = [[NSXPCListener alloc] initWithMachServiceName:DAEMON_MACH_SERVICE];\n        \n        //macOS 13+\n        // set code signing requirement for clients via 'setConnectionCodeSigningRequirement'\n        if(@available(macOS 13.0, *)) {\n        \n            //init requirement\n            // LuLu client, v2.0+\n            requirement = [NSString stringWithFormat:@\"anchor apple generic and identifier \\\"%@\\\" and certificate leaf [subject.CN] = \\\"%@\\\" and info [CFBundleShortVersionString] >= \\\"2.0.0\\\"\", APP_ID, SIGNING_AUTH];\n            \n            //set requirement\n            [self.listener setConnectionCodeSigningRequirement:requirement];\n            \n            //dbg msg\n            os_log_debug(logHandle, \"set XPC requirement %@\", requirement);\n            \n        }\n        \n        //dbg msg\n        os_log_debug(logHandle, \"created mach service %@\", DAEMON_MACH_SERVICE);\n        \n        //set delegate\n        self.listener.delegate = self;\n        \n        //ready to accept connections\n        [self.listener resume];\n    }\n    \n    return self;\n}\n\n#pragma mark -\n#pragma mark NSXPCConnection method overrides\n\n//automatically invoked\n// allows NSXPCListener to configure/accept/resume a new incoming NSXPCConnection\n// shoutout to writeup: https://blog.obdev.at/what-we-have-learned-from-a-vulnerability\n-(BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection\n{\n    //flag\n    BOOL shouldAccept = NO;\n    \n    //status\n    OSStatus status = !errSecSuccess;\n    \n    //audit token\n    audit_token_t auditToken = {0};\n    \n    //task ref\n    SecTaskRef taskRef = 0;\n    \n    //code ref\n    SecCodeRef codeRef = NULL;\n    \n    //code signing info\n    CFDictionaryRef csInfo = NULL;\n    \n    //cs flags\n    uint32_t csFlags = 0;\n    \n    //signing req string (main app)\n    NSString* requirement = nil;\n\n    //extract audit token\n    auditToken = ((ExtendedNSXPCConnection*)newConnection).auditToken;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"received request to connect to XPC interface from: (%d)%{public}@\", audit_token_to_pid(auditToken), getProcessPath(audit_token_to_pid(auditToken)));\n    \n    //obtain dynamic code ref\n    status = SecCodeCopyGuestWithAttributes(NULL, (__bridge CFDictionaryRef _Nullable)(@{(__bridge NSString *)kSecGuestAttributeAudit : [NSData dataWithBytes:&auditToken length:sizeof(audit_token_t)]}), kSecCSDefaultFlags, &codeRef);\n    if(errSecSuccess != status)\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: 'SecCodeCopyGuestWithAttributes' failed with': %#x\", status);\n        \n        //bail\n        goto bail;\n    }\n    \n    //validate code\n    status = SecCodeCheckValidity(codeRef, kSecCSDefaultFlags, NULL);\n    if(errSecSuccess != status)\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: 'SecCodeCheckValidity' failed with': %#x\", status);\n       \n        //bail\n        goto bail;\n    }\n    \n    //get code signing info\n    status = SecCodeCopySigningInformation(codeRef, kSecCSDynamicInformation, &csInfo);\n    if(errSecSuccess != status)\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: 'SecCodeCopySigningInformation' failed with': %#x\", status);\n       \n        //bail\n        goto bail;\n    }\n    \n    //dbg msg\n    os_log_debug(logHandle, \"client's code signing info: %{public}@\", csInfo);\n    \n    //extract flags\n    csFlags = [((__bridge NSDictionary *)csInfo)[(__bridge NSString *)kSecCodeInfoStatus] unsignedIntValue];\n    \n    //dbg msg\n    os_log_debug(logHandle, \"client code signing flags: %#x\", csFlags);\n    \n    //gotta have hardened runtime\n    if( !(CS_VALID & csFlags) &&\n        !(CS_RUNTIME & csFlags) )\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: invalid code signing flags: %#x\", csFlags);\n        \n        //bail\n        goto bail;\n    }\n    \n    //dbg msg\n    os_log_debug(logHandle, \"client code signing flags, ok (includes 'CS_RUNTIME')\");\n    \n    //init signing req\n    requirement = [NSString stringWithFormat:@\"anchor apple generic and identifier \\\"%@\\\" and certificate leaf [subject.CN] = \\\"%@\\\"\", APP_ID, SIGNING_AUTH];\n    \n    //step 1: create task ref\n    // uses NSXPCConnection's (private) 'auditToken' iVar\n    taskRef = SecTaskCreateWithAuditToken(NULL, ((ExtendedNSXPCConnection*)newConnection).auditToken);\n    if(NULL == taskRef)\n    {\n        //bail\n        goto bail;\n    }\n    \n    //step 2: validate\n    // check that client is signed with Objective-See's and it's LuLu\n    if(errSecSuccess != (status = SecTaskValidateForRequirement(taskRef, (__bridge CFStringRef)(requirement))))\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: failed with validate client (error: %#x/%d)\", status, status);\n    \n        //bail\n        goto bail;\n    }\n    \n    //dbg msg\n    os_log_debug(logHandle, \"client code signing information, ok\");\n    \n    //set the interface that the exported object implements\n    newConnection.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(XPCDaemonProtocol)];\n    \n    //set object exported by connection\n    newConnection.exportedObject = [[XPCDaemon alloc] init];\n    \n    //set type of remote object\n    // user (login item/main app) will set this object\n    newConnection.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol: @protocol(XPCUserProtocol)];\n    \n    //set interruption handler\n    [newConnection setInterruptionHandler:^{\n        \n        //dbg msg\n        os_log_debug(logHandle, \"XPC 'interruptionHandler' method invoked\");\n        \n        //unset user\n        alerts.consoleUser = nil;\n        \n    }];\n\n    //set invalidation handler\n    [newConnection setInvalidationHandler:^{\n        \n        //dbg msg\n        os_log_debug(logHandle, \"XPC 'invalidationHandler' method invoked\");\n        \n        //unset user\n        alerts.consoleUser = nil;\n        \n    }];\n    \n    //save\n    self.client = newConnection;\n    \n    //and set user\n    alerts.consoleUser = getConsoleUser();\n    \n    //resume\n    [newConnection resume];\n    \n    //dbg msg\n    os_log_debug(logHandle, \"allowing XPC connection from client (pid: %d, user: %{public}@)\", audit_token_to_pid(auditToken), alerts.consoleUser);\n    \n    //happy\n    shouldAccept = YES;\n    \nbail:\n    \n    //release task ref object\n    if(NULL != taskRef)\n    {\n        //release\n        CFRelease(taskRef);\n        taskRef = NULL;\n    }\n    \n    //free cs info\n    if(NULL != csInfo)\n    {\n        //free\n        CFRelease(csInfo);\n        csInfo = NULL;\n    }\n    \n    //free code ref\n    if(NULL != codeRef)\n    {\n        //free\n        CFRelease(codeRef);\n        codeRef = NULL;\n    }\n    \n    return shouldAccept;\n}\n\n@end\n"
  },
  {
    "path": "LuLu/Extension/XPCUserClient.h",
    "content": "//\n//  file: XPCUserClient.h\n//  project: lulu (launch daemon)\n//  description: talk to the user, via XPC (header)\n//\n//  created by Patrick Wardle\n//  copyright (c) 2018 Objective-See. All rights reserved.\n//\n\n@import OSLog;\n@import Foundation;\n\n#import \"XPCUserProto.h\"\n@interface XPCUserClient : NSObject\n{\n    \n}\n\n/* PROPERTIES */\n\n\n/* METHODS */\n\n//deliver alert to user\n// note: this is synchronous, so errors can be detected\n-(BOOL)deliverAlert:(NSDictionary*)alert reply:(void (^)(NSDictionary*))reply;\n\n//inform user rules have changed\n-(void)rulesChanged;\n\n@end\n"
  },
  {
    "path": "LuLu/Extension/XPCUserClient.m",
    "content": "//\n//  file: XPCUserClient.m\n//  project: lulu (launch daemon)\n//  description: talk to the user, via XPC (header)\n//\n//  created by Patrick Wardle\n//  copyright (c) 2018 Objective-See. All rights reserved.\n//\n\n#import \"Rules.h\"\n#import \"Alerts.h\"\n#import \"consts.h\"\n#import \"XPCListener.h\"\n#import \"XPCUserClient.h\"\n\n/* GLOBALS */\n\n//xpc connection\nextern XPCListener* xpcListener;\n\n//log handle\nextern os_log_t logHandle;\n\n@implementation XPCUserClient\n\n//deliver alert to user\n-(BOOL)deliverAlert:(NSDictionary*)alert reply:(void (^)(NSDictionary*))reply\n{\n    //flag\n    __block BOOL xpcError = NO;\n    \n    //sanity check\n    // no client connection?\n    if(nil == xpcListener.client)\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"no client is connected, alert will not be delivered\");\n        \n        //set error\n        xpcError = YES;\n        \n        //bail\n        //goto bail;\n    }\n    else\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"invoking user XPC method: 'alertShow:reply:'\");\n\n        //send to user\n        [[xpcListener.client remoteObjectProxyWithErrorHandler:^(NSError * proxyError)\n        {\n            //err msg\n            os_log_error(logHandle, \"ERROR: failed to execute daemon XPC method '%s' (error: %{public}@)\", __PRETTY_FUNCTION__, proxyError);\n            \n            //set error\n            xpcError = YES;\n            \n        }] alertShow:alert reply:^(NSDictionary* userReply)\n        {\n            //dbg msg\n            os_log_debug(logHandle, \"reply: %{public}@\", alert);\n            \n            //respond\n            reply(userReply);\n        }];\n    }\n\nbail:\n\n    return !xpcError;\n}\n\n//inform user rules have changed\n-(void)rulesChanged\n{\n    //dbg msg\n    os_log_debug(logHandle, \"invoking user XPC method, '%s'\", __PRETTY_FUNCTION__);\n    \n    //no client?\n    // no need to do anything...\n    if(nil == xpcListener.client)\n    {\n        //bail\n        goto bail;\n    }\n    \n    //send to user (login item) to display\n    [[xpcListener.client remoteObjectProxyWithErrorHandler:^(NSError * proxyError)\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: failed to execute 'rulesChanged' method on launch daemon (error: %{public}@)\", proxyError);\n          \n    }] rulesChanged];\n    \nbail:\n    \n    return;\n}\n\n@end\n"
  },
  {
    "path": "LuLu/Extension/main.h",
    "content": "//\n//  file: main.h\n//  project: lulu (launch daemon)\n//  description: main (header)\n//\n//  created by Patrick Wardle\n//  copyright (c) 2018 Objective-See. All rights reserved.\n//\n\n#import \"Rules.h\"\n#import \"Alerts.h\"\n#import \"consts.h\"\n#import \"Profiles.h\"\n#import \"utilities.h\"\n#import \"Preferences.h\"\n#import \"XPCListener.h\"\n#import \"BlockOrAllowList.h\"\n\n#ifndef main_h\n#define main_h\n\n//GLOBALS\n\n//rules obj\nRules* rules = nil;\n\n//alerts obj\nAlerts* alerts = nil;\n\n//allow list\nBlockOrAllowList* allowList = nil;\n\n//block list\nBlockOrAllowList* blockList = nil;\n\n//XPC listener obj\nXPCListener* xpcListener = nil;\n\n//prefs obj\nPreferences* preferences = nil;\n\n//profile obj\nProfiles* profiles = nil;\n\n//dispatch source for SIGTERM\ndispatch_source_t dispatchSource = nil;\n\n/* FUNCTIONS */\n\n//init a handler for SIGTERM\n// can perform actions such as disabling firewall and closing logging\nvoid register4Shutdown(void);\n\n//launch daemon should only be unloaded if box is shutting down\n// so handle things like telling kext to disable & unregister, de-init logging, etc\nvoid goodbye(void);\n\n\n#endif /* main_h */\n"
  },
  {
    "path": "LuLu/Extension/main.m",
    "content": "//\n//  main.m\n//  Extension\n//\n//  Created by Patrick Wardle on 8/1/20.\n//  Copyright (c) 2020 Objective-See. All rights reserved.\n//\n\n//FOR LOGGING:\n// % log stream --level debug --predicate=\"subsystem='com.objective-see.lulu'\"\n\n#import \"main.h\"\n\n@import OSLog;\n@import Foundation;\n@import NetworkExtension;\n\n/* GLOBALS */\n\n//log handle\nos_log_t logHandle = nil;\n\n//main\nint main(int argc, char *argv[])\n{\n    //pool\n    @autoreleasepool {\n    \n    //init log\n    logHandle = os_log_create(BUNDLE_ID, \"extension\");\n    \n    //dbg msg\n    os_log_debug(logHandle, \"started: %{public}@ (pid: %d / uid: %d)\", NSProcessInfo.processInfo.arguments.firstObject, getpid(), getuid());\n    \n    //start sysext\n    // Apple notes, \"call [this] as early as possible\"\n    [NEProvider startSystemExtensionMode];\n        \n    //dbg msg\n    os_log_debug(logHandle, \"enabled extension ('startSystemExtensionMode' was called)\");\n    \n    //alloc/init/load prefs\n    preferences = [[Preferences alloc] init];\n            \n    //alloc/init alerts object\n    alerts = [[Alerts alloc] init];\n    \n    //alloc/init rules object\n    rules = [[Rules alloc] init];\n    \n    //alloc/init profiles object\n    profiles = [[Profiles alloc] init];\n        \n    //alloc/init XPC comms object\n    xpcListener = [[XPCListener alloc] init];\n        \n    //dbg msg\n    os_log_debug(logHandle, \"created client XPC listener\");\n    \n    //need to create\n    // create install directory?\n    if(YES != [[NSFileManager defaultManager] fileExistsAtPath:INSTALL_DIRECTORY])\n    {\n        //create it\n        if(YES != [[NSFileManager defaultManager] createDirectoryAtPath:INSTALL_DIRECTORY withIntermediateDirectories:YES attributes:nil error:NULL])\n        {\n            //err msg\n            os_log_error(logHandle, \"ERROR: failed to create install directory, %{public}@\", INSTALL_DIRECTORY);\n            \n            //bail\n            goto bail;\n        }\n    }\n        \n    //prep rules\n    // first time? generate defaults rules\n    // upgrade (v1.0)? convert to new format\n    [rules prepare];\n    \n    //load rules\n    // if this fails, falls back to (re)generating default rules\n    if(YES != [rules load])\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: failed to load rules from %{public}@ ...will defaulting back to defualt rules\", RULES_FILE);\n        \n        //generate default rules\n        if(YES != [rules generateDefaultRules])\n        {\n            //err msg\n            os_log_error(logHandle, \"ERROR: failed to generate default rules\");\n            \n            //bail\n            goto bail;\n        }\n        \n        //save\n        [rules save];\n        \n        //(re)load rules\n        if(YES != [rules load]) {\n            \n            //err msg\n            os_log_error(logHandle, \"ERROR: failed again to load rules from %{public}@ ...will exit!\", RULES_FILE);\n            \n            //bail\n            goto bail;\n        }\n    }\n    \n    //allow list?\n    if(0 != preferences.preferences[PREF_USE_ALLOW_LIST])\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"init'ing allowing list\");\n        \n        //alloc/init/load allow list\n        allowList = [[BlockOrAllowList alloc] init:preferences.preferences[PREF_ALLOW_LIST]];\n    }\n        \n    //block list?\n    if(0 != preferences.preferences[PREF_USE_BLOCK_LIST])\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"init'ing block list\");\n        \n        //alloc/init/load block list\n        blockList = [[BlockOrAllowList alloc] init:preferences.preferences[PREF_BLOCK_LIST]];\n    }\n    \n    }//pool\n    \n    dispatch_main();\n               \nbail:\n    \n    return 0;\n}\n"
  },
  {
    "path": "LuLu/Extension/procInfo.h",
    "content": "//\n//  File: procInfo.h\n//  Project: Proc Info\n//\n//  Created by: Patrick Wardle\n//  Copyright:  2017 Objective-See\n//  License:    Creative Commons Attribution-NonCommercial 4.0 International License\n//\n\n#ifndef procInfo_h\n#define procInfo_h\n\n#import <libproc.h>\n#import <sys/sysctl.h>\n#import <Foundation/Foundation.h>\n\n/* CLASSES */\n\n@class Binary;\n@class Process;\n\n/* DEFINES */\n\n//from audit_kevents.h\n#define EVENT_EXIT\t\t1\n#define\tEVENT_FORK      2   \n#define EVENT_EXECVE    23\n#define EVENT_EXEC      27\n#define EVENT_SPAWN     43190\n\n//signers\nenum Signer{None, Apple, AppStore, DevID, AdHoc};\n\n//signature status\n#define KEY_SIGNATURE_STATUS @\"signatureStatus\"\n\n//signer\n#define KEY_SIGNATURE_SIGNER @\"signatureSigner\"\n\n//signing auths\n#define KEY_SIGNATURE_AUTHORITIES @\"signatureAuthorities\"\n\n//code signing id\n#define KEY_SIGNATURE_IDENTIFIER @\"signatureIdentifier\"\n\n//entitlements\n#define KEY_SIGNATURE_ENTITLEMENTS @\"signatureEntitlements\"\n\n/* TYPEDEFS */\n\n//block for library\ntypedef void (^ProcessCallbackBlock)(Process* _Nonnull);\n\n/* OBJECT: PROCESS INFO */\n\n@interface ProcInfo : NSObject\n\n//init w/ flag\n// flag dictates if CPU-intensive logic (code signing, etc) should be preformed\n-(id _Nullable)init:(BOOL)goEasy;\n\n//start monitoring\n-(void)start:(ProcessCallbackBlock _Nonnull )callback;\n\n//stop monitoring\n-(void)stop;\n\n//get list of running processes\n-(NSMutableArray* _Nonnull)currentProcesses;\n\n@end\n\n/* OBJECT: PROCESS */\n\n@interface Process : NSObject\n\n/* PROPERTIES */\n\n//pid\n@property pid_t pid;\n\n//ppid\n@property pid_t ppid;\n\n//user id\n@property uid_t uid;\n\n//type\n// used by process mon\n@property u_int16_t type;\n\n//exit code\n@property u_int32_t exit;\n\n//path\n@property(nonatomic, retain)NSString* _Nullable path;\n\n//args\n@property(nonatomic, retain)NSMutableArray* _Nonnull arguments;\n\n//ancestors\n@property(nonatomic, retain)NSMutableArray* _Nonnull ancestors;\n\n//signing info\n@property(nonatomic, retain)NSMutableDictionary* _Nonnull signingInfo;\n\n//Binary object\n// has path, hash, etc\n@property(nonatomic, retain)Binary* _Nonnull binary;\n\n//timestamp\n@property(nonatomic, retain)NSDate* _Nonnull timestamp;\n\n/* METHODS */\n\n//init with a pid\n// method will then (try) fill out rest of object\n-(id _Nullable)init:(pid_t)processID;\n\n//generate signing info\n// also classifies if Apple/from App Store/etc.\n-(void)generateSigningInfo:(SecCSFlags)flags;\n\n//set process's path\n-(void)pathFromPid;\n\n//generate list of ancestors\n-(void)enumerateAncestors;\n\n//class method\n// get's parent of arbitrary process\n+(pid_t)getParentID:(pid_t)child;\n\n@end\n\n/* OBJECT: BINARY */\n\n@interface Binary : NSObject\n{\n    \n}\n\n/* PROPERTIES */\n\n//path\n@property(nonatomic, retain)NSString* _Nonnull path;\n\n//name\n@property(nonatomic, retain)NSString* _Nonnull name;\n\n//icon\n@property(nonatomic, retain)NSImage* _Nonnull icon;\n\n//file attributes\n@property(nonatomic, retain)NSDictionary* _Nullable attributes;\n\n//spotlight meta data\n@property(nonatomic, retain)NSDictionary* _Nullable metadata;\n\n//bundle\n// nil for non-apps\n@property(nonatomic, retain)NSBundle* _Nullable bundle;\n\n//signing info\n@property(nonatomic, retain)NSDictionary* _Nonnull signingInfo;\n\n//hash\n@property(nonatomic, retain)NSMutableString* _Nonnull sha256;\n\n//identifier\n// either signing id or sha256 hash\n@property(nonatomic, retain)NSString* _Nonnull identifier;\n\n/* METHODS */\n\n//init w/ a path\n-(id _Nonnull)init:(NSString* _Nonnull)path;\n\n/* the following methods are rather CPU-intensive\n   as such, if the proc monitoring is run with the 'goEasy' option, they aren't automatically invoked\n*/\n \n//get an icon for a process\n// for apps, this will be app's icon, otherwise just a standard system one\n-(void)getIcon;\n\n//generate signing info (statically)\n-(void)generateSigningInfo:(SecCSFlags)flags;\n\n/* the following methods are not invoked automatically\n   as such, if you code has to manually invoke them if you want this info\n */\n\n//generate hash\n// algo: sha256\n-(void)generateHash;\n\n//generate id\n// either signing id, or sha256 hash\n-(void)generateIdentifier;\n\n@end\n\n#endif\n"
  },
  {
    "path": "LuLu/LuLu.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 60;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\tCD0070262C3954220011979F /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = CD0070252C3954220011979F /* Localizable.xcstrings */; };\n\t\tCD0070272C3954220011979F /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = CD0070252C3954220011979F /* Localizable.xcstrings */; };\n\t\tCD00702C2C3956F50011979F /* Welcome.xib in Resources */ = {isa = PBXBuildFile; fileRef = CD00702B2C3956F50011979F /* Welcome.xib */; };\n\t\tCD0070302C3959970011979F /* Rules.xib in Resources */ = {isa = PBXBuildFile; fileRef = CD00702F2C3959970011979F /* Rules.xib */; };\n\t\tCD0070342C39599E0011979F /* StartupWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = CD0070332C39599E0011979F /* StartupWindowController.xib */; };\n\t\tCD0070382C3959A90011979F /* StatusBarPopover.xib in Resources */ = {isa = PBXBuildFile; fileRef = CD0070372C3959A90011979F /* StatusBarPopover.xib */; };\n\t\tCD00703C2C3959B90011979F /* UpdateWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = CD00703B2C3959B90011979F /* UpdateWindow.xib */; };\n\t\tCD03F8F524F8E68300723BDC /* Binary.m in Sources */ = {isa = PBXBuildFile; fileRef = CD03F8F324F8E68300723BDC /* Binary.m */; };\n\t\tCD03F8F624F8E68300723BDC /* Process.m in Sources */ = {isa = PBXBuildFile; fileRef = CD03F8F424F8E68300723BDC /* Process.m */; };\n\t\tCD21D37A252FE91E001A19A8 /* signing.m in Sources */ = {isa = PBXBuildFile; fileRef = CD21D379252FE91E001A19A8 /* signing.m */; };\n\t\tCD21D37D252FE94F001A19A8 /* signing.m in Sources */ = {isa = PBXBuildFile; fileRef = CD21D37B252FE94F001A19A8 /* signing.m */; };\n\t\tCD2CA1742C3E9E4300D7BEAA /* Preferences.xib in Resources */ = {isa = PBXBuildFile; fileRef = CD2CA1732C3E9E4300D7BEAA /* Preferences.xib */; };\n\t\tCD2CA1782C3E9E5700D7BEAA /* ItemPaths.xib in Resources */ = {isa = PBXBuildFile; fileRef = CD2CA1772C3E9E5700D7BEAA /* ItemPaths.xib */; };\n\t\tCD2CA17E2C3E9E6700D7BEAA /* AlertWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = CD2CA17D2C3E9E6700D7BEAA /* AlertWindow.xib */; };\n\t\tCD2CA1822C3E9E6C00D7BEAA /* AddRule.xib in Resources */ = {isa = PBXBuildFile; fileRef = CD2CA1812C3E9E6C00D7BEAA /* AddRule.xib */; };\n\t\tCD2CA1862C3E9E7000D7BEAA /* AboutWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = CD2CA1852C3E9E7000D7BEAA /* AboutWindow.xib */; };\n\t\tCD2CA1912C3E9F0A00D7BEAA /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = CD2CA1902C3E9F0A00D7BEAA /* MainMenu.xib */; };\n\t\tCD9E04D3254163AF00DB3218 /* patrons.txt in Resources */ = {isa = PBXBuildFile; fileRef = CDA1369624F0D2CF005AD424 /* patrons.txt */; };\n\t\tCD9E147D25171BF200DA05C3 /* ItemPathsWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = CD9E147B25171BF200DA05C3 /* ItemPathsWindowController.m */; };\n\t\tCD9F567F252533CE00F3DEB5 /* NSApplicationKeyEvents.m in Sources */ = {isa = PBXBuildFile; fileRef = CD9F567E252533CD00F3DEB5 /* NSApplicationKeyEvents.m */; };\n\t\tCDA1364624EF4DA1005AD424 /* utilities.m in Sources */ = {isa = PBXBuildFile; fileRef = CDA1363324EF4DA0005AD424 /* utilities.m */; };\n\t\tCDA1364824EF4DA1005AD424 /* Rule.m in Sources */ = {isa = PBXBuildFile; fileRef = CDA1363724EF4DA0005AD424 /* Rule.m */; };\n\t\tCDA1366224EF4E57005AD424 /* XPCUserClient.m in Sources */ = {isa = PBXBuildFile; fileRef = CDA1364D24EF4E56005AD424 /* XPCUserClient.m */; };\n\t\tCDA1366324EF4E57005AD424 /* Alerts.m in Sources */ = {isa = PBXBuildFile; fileRef = CDA1364F24EF4E56005AD424 /* Alerts.m */; };\n\t\tCDA1366424EF4E57005AD424 /* GrayList.m in Sources */ = {isa = PBXBuildFile; fileRef = CDA1365124EF4E56005AD424 /* GrayList.m */; };\n\t\tCDA1366624EF4E57005AD424 /* Preferences.m in Sources */ = {isa = PBXBuildFile; fileRef = CDA1365324EF4E56005AD424 /* Preferences.m */; };\n\t\tCDA1366724EF4E57005AD424 /* XPCDaemon.m in Sources */ = {isa = PBXBuildFile; fileRef = CDA1365624EF4E56005AD424 /* XPCDaemon.m */; };\n\t\tCDA1366824EF4E57005AD424 /* XPCListener.m in Sources */ = {isa = PBXBuildFile; fileRef = CDA1365724EF4E56005AD424 /* XPCListener.m */; };\n\t\tCDA1366D24EF4F89005AD424 /* Rules.m in Sources */ = {isa = PBXBuildFile; fileRef = CDA1366C24EF4F89005AD424 /* Rules.m */; };\n\t\tCDA1366F24EF5587005AD424 /* libbsm.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = CDA1366E24EF5587005AD424 /* libbsm.tbd */; };\n\t\tCDA136C724F0D7C3005AD424 /* utilities.m in Sources */ = {isa = PBXBuildFile; fileRef = CDA136C524F0D7C3005AD424 /* utilities.m */; };\n\t\tCDA136CD24F0D94F005AD424 /* XPCUser.m in Sources */ = {isa = PBXBuildFile; fileRef = CDA136CC24F0D94F005AD424 /* XPCUser.m */; };\n\t\tCDA136D024F0D9C1005AD424 /* XPCDaemonClient.m in Sources */ = {isa = PBXBuildFile; fileRef = CDA136CF24F0D9C1005AD424 /* XPCDaemonClient.m */; };\n\t\tCDA136D124F0DA0E005AD424 /* Update.m in Sources */ = {isa = PBXBuildFile; fileRef = CDA136B424F0D4A8005AD424 /* Update.m */; };\n\t\tCDA136D224F0DA0E005AD424 /* UpdateWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = CDA136B324F0D4A8005AD424 /* UpdateWindowController.m */; };\n\t\tCDA136D324F0DA0E005AD424 /* AboutWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = CDA1369524F0D2CF005AD424 /* AboutWindowController.m */; };\n\t\tCDA136D424F0DA0E005AD424 /* AddRuleWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = CDA1369A24F0D2CF005AD424 /* AddRuleWindowController.m */; };\n\t\tCDA136D524F0DA0E005AD424 /* PrefsWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = CDA1368E24F0D2CF005AD424 /* PrefsWindowController.m */; };\n\t\tCDA136D624F0DA0E005AD424 /* RuleRow.m in Sources */ = {isa = PBXBuildFile; fileRef = CDA1369E24F0D2CF005AD424 /* RuleRow.m */; };\n\t\tCDA136D924F0DA0E005AD424 /* RulesWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = CDA1369C24F0D2CF005AD424 /* RulesWindowController.m */; };\n\t\tCDA136DA24F0DA0E005AD424 /* WelcomeWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = CDA1369924F0D2CF005AD424 /* WelcomeWindowController.m */; };\n\t\tCDA136DB24F0DA0E005AD424 /* AlertWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = CDA1367224F0D268005AD424 /* AlertWindowController.m */; };\n\t\tCDA136DD24F0DA0F005AD424 /* ParentsWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = CDA1367E24F0D268005AD424 /* ParentsWindowController.m */; };\n\t\tCDA136DE24F0DA0F005AD424 /* SigningInfoViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = CDA1367524F0D268005AD424 /* SigningInfoViewController.m */; };\n\t\tCDA136DF24F0DA0F005AD424 /* StatusBarItem.m in Sources */ = {isa = PBXBuildFile; fileRef = CDA1368024F0D268005AD424 /* StatusBarItem.m */; };\n\t\tCDA136E024F0DA0F005AD424 /* StatusBarPopoverController.m in Sources */ = {isa = PBXBuildFile; fileRef = CDA1367C24F0D268005AD424 /* StatusBarPopoverController.m */; };\n\t\tCDA136E524F0DA43005AD424 /* Rule.m in Sources */ = {isa = PBXBuildFile; fileRef = CDA136E424F0DA43005AD424 /* Rule.m */; };\n\t\tCDB2CC1D24D61A4E00D0EECE /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = CDB2CC1C24D61A4E00D0EECE /* AppDelegate.m */; };\n\t\tCDB2CC1F24D61A5000D0EECE /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CDB2CC1E24D61A5000D0EECE /* Assets.xcassets */; };\n\t\tCDB2CC2524D61A5000D0EECE /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = CDB2CC2424D61A5000D0EECE /* main.m */; };\n\t\tCDB2CC3324D61B3900D0EECE /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CDB2CC3224D61B3900D0EECE /* NetworkExtension.framework */; };\n\t\tCDB2CC3724D61B3900D0EECE /* FilterDataProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = CDB2CC3624D61B3900D0EECE /* FilterDataProvider.m */; };\n\t\tCDB2CC3924D61B3900D0EECE /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = CDB2CC3824D61B3900D0EECE /* main.m */; };\n\t\tCDB2CC3E24D61B3900D0EECE /* com.objective-see.lulu.extension.systemextension in Embed System Extensions */ = {isa = PBXBuildFile; fileRef = CDB2CC3024D61B3900D0EECE /* com.objective-see.lulu.extension.systemextension */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };\n\t\tCDB2CC4424DBE48100D0EECE /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CDB2CC3224D61B3900D0EECE /* NetworkExtension.framework */; };\n\t\tCDB909EB2B72BC230043FEB4 /* Configure.m in Sources */ = {isa = PBXBuildFile; fileRef = CDB909EA2B72BC230043FEB4 /* Configure.m */; };\n\t\tCDC378C7250C66C300314064 /* Extension.m in Sources */ = {isa = PBXBuildFile; fileRef = CDC378C6250C66C300314064 /* Extension.m */; };\n\t\tCDC378CB250C83F200314064 /* Netiquette.app in Resources */ = {isa = PBXBuildFile; fileRef = CDC378C9250C83F100314064 /* Netiquette.app */; };\n\t\tCDC41C412503424800CB302B /* OrderedDictionary.m in Sources */ = {isa = PBXBuildFile; fileRef = CDC41C3F2503424800CB302B /* OrderedDictionary.m */; };\n\t\tCDCAA9692B677AFC00FE27DD /* StartupWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = CDCAA9662B677AFC00FE27DD /* StartupWindowController.m */; };\n\t\tCDCAA96C2B69DC3700FE27DD /* RulesMenuController.m in Sources */ = {isa = PBXBuildFile; fileRef = CDCAA96B2B69DC3700FE27DD /* RulesMenuController.m */; };\n\t\tCDD7853D255609AC001BB0BE /* BlockOrAllowList.m in Sources */ = {isa = PBXBuildFile; fileRef = CDD7853C255609AC001BB0BE /* BlockOrAllowList.m */; };\n\t\tCDD992D72C4EC30000A1B406 /* InfoPlist.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = CDD992D62C4EC30000A1B406 /* InfoPlist.xcstrings */; };\n\t\tCDEA3AD22E0724EC00FDD0C0 /* Profiles.m in Sources */ = {isa = PBXBuildFile; fileRef = CDEA3AD12E0724EC00FDD0C0 /* Profiles.m */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXContainerItemProxy section */\n\t\tCDB2CC3C24D61B3900D0EECE /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = CDB2CC1024D61A4E00D0EECE /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = CDB2CC2F24D61B3900D0EECE;\n\t\t\tremoteInfo = Extension;\n\t\t};\n/* End PBXContainerItemProxy section */\n\n/* Begin PBXCopyFilesBuildPhase section */\n\t\tCDB2CC4224D61B3900D0EECE /* Embed System Extensions */ = {\n\t\t\tisa = PBXCopyFilesBuildPhase;\n\t\t\tbuildActionMask = 12;\n\t\t\tdstPath = \"$(SYSTEM_EXTENSIONS_FOLDER_PATH)\";\n\t\t\tdstSubfolderSpec = 16;\n\t\t\tfiles = (\n\t\t\t\tCDB2CC3E24D61B3900D0EECE /* com.objective-see.lulu.extension.systemextension in Embed System Extensions */,\n\t\t\t);\n\t\t\tname = \"Embed System Extensions\";\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXCopyFilesBuildPhase section */\n\n/* Begin PBXFileReference section */\n\t\tCD0070252C3954220011979F /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; name = Localizable.xcstrings; path = Shared/Localizable.xcstrings; sourceTree = \"<group>\"; };\n\t\tCD00702A2C3956F50011979F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/Welcome.xib; sourceTree = \"<group>\"; };\n\t\tCD00702D2C3956F50011979F /* mul */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; name = mul; path = mul.lproj/Welcome.xcstrings; sourceTree = \"<group>\"; };\n\t\tCD00702E2C3959970011979F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/Rules.xib; sourceTree = \"<group>\"; };\n\t\tCD0070312C3959970011979F /* mul */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; name = mul; path = mul.lproj/Rules.xcstrings; sourceTree = \"<group>\"; };\n\t\tCD0070322C39599E0011979F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/StartupWindowController.xib; sourceTree = \"<group>\"; };\n\t\tCD0070352C39599E0011979F /* mul */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; name = mul; path = mul.lproj/StartupWindowController.xcstrings; sourceTree = \"<group>\"; };\n\t\tCD0070362C3959A90011979F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/StatusBarPopover.xib; sourceTree = \"<group>\"; };\n\t\tCD0070392C3959A90011979F /* mul */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; name = mul; path = mul.lproj/StatusBarPopover.xcstrings; sourceTree = \"<group>\"; };\n\t\tCD00703A2C3959B90011979F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/UpdateWindow.xib; sourceTree = \"<group>\"; };\n\t\tCD00703D2C3959B90011979F /* mul */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; name = mul; path = mul.lproj/UpdateWindow.xcstrings; sourceTree = \"<group>\"; };\n\t\tCD03F8F324F8E68300723BDC /* Binary.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Binary.m; sourceTree = \"<group>\"; };\n\t\tCD03F8F424F8E68300723BDC /* Process.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Process.m; sourceTree = \"<group>\"; };\n\t\tCD03F8FA24F8E6BD00723BDC /* Binary.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Binary.h; sourceTree = \"<group>\"; };\n\t\tCD03F8FB24F8E6C600723BDC /* Process.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Process.h; sourceTree = \"<group>\"; };\n\t\tCD21D378252FE91E001A19A8 /* signing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = signing.h; path = Shared/signing.h; sourceTree = SOURCE_ROOT; };\n\t\tCD21D379252FE91E001A19A8 /* signing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = signing.m; path = Shared/signing.m; sourceTree = SOURCE_ROOT; };\n\t\tCD21D37B252FE94F001A19A8 /* signing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = signing.m; path = Shared/signing.m; sourceTree = SOURCE_ROOT; };\n\t\tCD21D37C252FE94F001A19A8 /* signing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = signing.h; path = Shared/signing.h; sourceTree = SOURCE_ROOT; };\n\t\tCD2CA1722C3E9E4300D7BEAA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/Preferences.xib; sourceTree = \"<group>\"; };\n\t\tCD2CA1752C3E9E4300D7BEAA /* mul */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; name = mul; path = mul.lproj/Preferences.xcstrings; sourceTree = \"<group>\"; };\n\t\tCD2CA1762C3E9E5700D7BEAA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/ItemPaths.xib; sourceTree = \"<group>\"; };\n\t\tCD2CA1792C3E9E5700D7BEAA /* mul */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; name = mul; path = mul.lproj/ItemPaths.xcstrings; sourceTree = \"<group>\"; };\n\t\tCD2CA17C2C3E9E6700D7BEAA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/AlertWindow.xib; sourceTree = \"<group>\"; };\n\t\tCD2CA17F2C3E9E6700D7BEAA /* mul */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; name = mul; path = mul.lproj/AlertWindow.xcstrings; sourceTree = \"<group>\"; };\n\t\tCD2CA1802C3E9E6C00D7BEAA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/AddRule.xib; sourceTree = \"<group>\"; };\n\t\tCD2CA1832C3E9E6C00D7BEAA /* mul */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; name = mul; path = mul.lproj/AddRule.xcstrings; sourceTree = \"<group>\"; };\n\t\tCD2CA1842C3E9E7000D7BEAA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/AboutWindow.xib; sourceTree = \"<group>\"; };\n\t\tCD2CA1872C3E9E7000D7BEAA /* mul */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; name = mul; path = mul.lproj/AboutWindow.xcstrings; sourceTree = \"<group>\"; };\n\t\tCD2CA18A2C3E9ED700D7BEAA /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = Base; path = Base.lproj/Extension.entitlements; sourceTree = \"<group>\"; };\n\t\tCD2CA18C2C3E9EF200D7BEAA /* App.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = App.entitlements; sourceTree = \"<group>\"; };\n\t\tCD2CA18F2C3E9F0A00D7BEAA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = \"<group>\"; };\n\t\tCD2CA1922C3E9F0A00D7BEAA /* mul */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; name = mul; path = mul.lproj/MainMenu.xcstrings; sourceTree = \"<group>\"; };\n\t\tCD9E147A25171BF200DA05C3 /* ItemPathsWindowController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ItemPathsWindowController.h; sourceTree = \"<group>\"; };\n\t\tCD9E147B25171BF200DA05C3 /* ItemPathsWindowController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ItemPathsWindowController.m; sourceTree = \"<group>\"; };\n\t\tCD9F567D252533CD00F3DEB5 /* NSApplicationKeyEvents.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSApplicationKeyEvents.h; sourceTree = \"<group>\"; };\n\t\tCD9F567E252533CD00F3DEB5 /* NSApplicationKeyEvents.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSApplicationKeyEvents.m; sourceTree = \"<group>\"; };\n\t\tCDA1363224EF4DA0005AD424 /* utilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = utilities.h; path = Shared/utilities.h; sourceTree = SOURCE_ROOT; };\n\t\tCDA1363324EF4DA0005AD424 /* utilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = utilities.m; path = Shared/utilities.m; sourceTree = SOURCE_ROOT; };\n\t\tCDA1363424EF4DA0005AD424 /* XPCDaemonProto.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = XPCDaemonProto.h; path = Shared/XPCDaemonProto.h; sourceTree = SOURCE_ROOT; };\n\t\tCDA1363724EF4DA0005AD424 /* Rule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Rule.m; path = Shared/Rule.m; sourceTree = SOURCE_ROOT; };\n\t\tCDA1363824EF4DA0005AD424 /* Rule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Rule.h; path = Shared/Rule.h; sourceTree = SOURCE_ROOT; };\n\t\tCDA1363A24EF4DA0005AD424 /* consts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = consts.h; path = Shared/consts.h; sourceTree = SOURCE_ROOT; };\n\t\tCDA1364124EF4DA1005AD424 /* XPCUserProto.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = XPCUserProto.h; path = Shared/XPCUserProto.h; sourceTree = SOURCE_ROOT; };\n\t\tCDA1364D24EF4E56005AD424 /* XPCUserClient.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XPCUserClient.m; sourceTree = \"<group>\"; };\n\t\tCDA1364F24EF4E56005AD424 /* Alerts.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Alerts.m; sourceTree = \"<group>\"; };\n\t\tCDA1365024EF4E56005AD424 /* main.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = main.h; sourceTree = \"<group>\"; };\n\t\tCDA1365124EF4E56005AD424 /* GrayList.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GrayList.m; sourceTree = \"<group>\"; };\n\t\tCDA1365324EF4E56005AD424 /* Preferences.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Preferences.m; sourceTree = \"<group>\"; };\n\t\tCDA1365624EF4E56005AD424 /* XPCDaemon.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XPCDaemon.m; sourceTree = \"<group>\"; };\n\t\tCDA1365724EF4E56005AD424 /* XPCListener.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XPCListener.m; sourceTree = \"<group>\"; };\n\t\tCDA1365924EF4E56005AD424 /* XPCUserClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XPCUserClient.h; sourceTree = \"<group>\"; };\n\t\tCDA1365A24EF4E56005AD424 /* Alerts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Alerts.h; sourceTree = \"<group>\"; };\n\t\tCDA1365B24EF4E57005AD424 /* Preferences.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Preferences.h; sourceTree = \"<group>\"; };\n\t\tCDA1365C24EF4E57005AD424 /* XPCListener.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XPCListener.h; sourceTree = \"<group>\"; };\n\t\tCDA1365D24EF4E57005AD424 /* GrayList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GrayList.h; sourceTree = \"<group>\"; };\n\t\tCDA1365E24EF4E57005AD424 /* XPCDaemon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XPCDaemon.h; sourceTree = \"<group>\"; };\n\t\tCDA1366B24EF4F89005AD424 /* Rules.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Rules.h; sourceTree = \"<group>\"; };\n\t\tCDA1366C24EF4F89005AD424 /* Rules.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Rules.m; sourceTree = \"<group>\"; };\n\t\tCDA1366E24EF5587005AD424 /* libbsm.tbd */ = {isa = PBXFileReference; lastKnownFileType = \"sourcecode.text-based-dylib-definition\"; name = libbsm.tbd; path = usr/lib/libbsm.tbd; sourceTree = SDKROOT; };\n\t\tCDA1367224F0D268005AD424 /* AlertWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AlertWindowController.m; sourceTree = \"<group>\"; };\n\t\tCDA1367524F0D268005AD424 /* SigningInfoViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SigningInfoViewController.m; sourceTree = \"<group>\"; };\n\t\tCDA1367724F0D268005AD424 /* StatusBarPopoverController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StatusBarPopoverController.h; sourceTree = \"<group>\"; };\n\t\tCDA1367824F0D268005AD424 /* SigningInfoViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SigningInfoViewController.h; sourceTree = \"<group>\"; };\n\t\tCDA1367A24F0D268005AD424 /* ParentsWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParentsWindowController.h; sourceTree = \"<group>\"; };\n\t\tCDA1367C24F0D268005AD424 /* StatusBarPopoverController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = StatusBarPopoverController.m; sourceTree = \"<group>\"; };\n\t\tCDA1367E24F0D268005AD424 /* ParentsWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ParentsWindowController.m; sourceTree = \"<group>\"; };\n\t\tCDA1367F24F0D268005AD424 /* AlertWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AlertWindowController.h; sourceTree = \"<group>\"; };\n\t\tCDA1368024F0D268005AD424 /* StatusBarItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = StatusBarItem.m; sourceTree = \"<group>\"; };\n\t\tCDA1368224F0D269005AD424 /* StatusBarItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StatusBarItem.h; sourceTree = \"<group>\"; };\n\t\tCDA1368E24F0D2CF005AD424 /* PrefsWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PrefsWindowController.m; sourceTree = \"<group>\"; };\n\t\tCDA1368F24F0D2CF005AD424 /* RulesWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RulesWindowController.h; sourceTree = \"<group>\"; };\n\t\tCDA1369224F0D2CF005AD424 /* PrefsWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PrefsWindowController.h; sourceTree = \"<group>\"; };\n\t\tCDA1369324F0D2CF005AD424 /* AddRuleWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AddRuleWindowController.h; sourceTree = \"<group>\"; };\n\t\tCDA1369524F0D2CF005AD424 /* AboutWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AboutWindowController.m; sourceTree = \"<group>\"; };\n\t\tCDA1369624F0D2CF005AD424 /* patrons.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = patrons.txt; sourceTree = \"<group>\"; };\n\t\tCDA1369724F0D2CF005AD424 /* WelcomeWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WelcomeWindowController.h; sourceTree = \"<group>\"; };\n\t\tCDA1369924F0D2CF005AD424 /* WelcomeWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WelcomeWindowController.m; sourceTree = \"<group>\"; };\n\t\tCDA1369A24F0D2CF005AD424 /* AddRuleWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AddRuleWindowController.m; sourceTree = \"<group>\"; };\n\t\tCDA1369B24F0D2CF005AD424 /* AboutWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AboutWindowController.h; sourceTree = \"<group>\"; };\n\t\tCDA1369C24F0D2CF005AD424 /* RulesWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RulesWindowController.m; sourceTree = \"<group>\"; };\n\t\tCDA1369D24F0D2CF005AD424 /* RuleRow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RuleRow.h; sourceTree = \"<group>\"; };\n\t\tCDA1369E24F0D2CF005AD424 /* RuleRow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RuleRow.m; sourceTree = \"<group>\"; };\n\t\tCDA136B324F0D4A8005AD424 /* UpdateWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UpdateWindowController.m; sourceTree = \"<group>\"; };\n\t\tCDA136B424F0D4A8005AD424 /* Update.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Update.m; sourceTree = \"<group>\"; };\n\t\tCDA136B524F0D4A9005AD424 /* Update.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Update.h; sourceTree = \"<group>\"; };\n\t\tCDA136B624F0D4A9005AD424 /* UpdateWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UpdateWindowController.h; sourceTree = \"<group>\"; };\n\t\tCDA136C424F0D7C3005AD424 /* utilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = utilities.h; path = Shared/utilities.h; sourceTree = SOURCE_ROOT; };\n\t\tCDA136C524F0D7C3005AD424 /* utilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = utilities.m; path = Shared/utilities.m; sourceTree = SOURCE_ROOT; };\n\t\tCDA136C624F0D7C3005AD424 /* consts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = consts.h; path = Shared/consts.h; sourceTree = SOURCE_ROOT; };\n\t\tCDA136CB24F0D94F005AD424 /* XPCUser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XPCUser.h; sourceTree = \"<group>\"; };\n\t\tCDA136CC24F0D94F005AD424 /* XPCUser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XPCUser.m; sourceTree = \"<group>\"; };\n\t\tCDA136CE24F0D9C1005AD424 /* XPCDaemonClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XPCDaemonClient.h; sourceTree = \"<group>\"; };\n\t\tCDA136CF24F0D9C1005AD424 /* XPCDaemonClient.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XPCDaemonClient.m; sourceTree = \"<group>\"; };\n\t\tCDA136E324F0DA43005AD424 /* Rule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Rule.h; path = Shared/Rule.h; sourceTree = SOURCE_ROOT; };\n\t\tCDA136E424F0DA43005AD424 /* Rule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Rule.m; path = Shared/Rule.m; sourceTree = SOURCE_ROOT; };\n\t\tCDB2CC1824D61A4E00D0EECE /* LuLu.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = LuLu.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tCDB2CC1B24D61A4E00D0EECE /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = \"<group>\"; };\n\t\tCDB2CC1C24D61A4E00D0EECE /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = \"<group>\"; };\n\t\tCDB2CC1E24D61A5000D0EECE /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\tCDB2CC2324D61A5000D0EECE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\tCDB2CC2424D61A5000D0EECE /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = \"<group>\"; };\n\t\tCDB2CC3024D61B3900D0EECE /* com.objective-see.lulu.extension.systemextension */ = {isa = PBXFileReference; explicitFileType = \"wrapper.system-extension\"; includeInIndex = 0; path = \"com.objective-see.lulu.extension.systemextension\"; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tCDB2CC3224D61B3900D0EECE /* NetworkExtension.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = NetworkExtension.framework; path = System/Library/Frameworks/NetworkExtension.framework; sourceTree = SDKROOT; };\n\t\tCDB2CC3524D61B3900D0EECE /* FilterDataProvider.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FilterDataProvider.h; sourceTree = \"<group>\"; };\n\t\tCDB2CC3624D61B3900D0EECE /* FilterDataProvider.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FilterDataProvider.m; sourceTree = \"<group>\"; };\n\t\tCDB2CC3824D61B3900D0EECE /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = \"<group>\"; };\n\t\tCDB2CC3A24D61B3900D0EECE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\tCDB909EA2B72BC230043FEB4 /* Configure.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Configure.m; sourceTree = \"<group>\"; };\n\t\tCDB909EC2B72BC2E0043FEB4 /* Configure.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Configure.h; sourceTree = \"<group>\"; };\n\t\tCDC378C5250C66C200314064 /* Extension.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Extension.h; sourceTree = \"<group>\"; };\n\t\tCDC378C6250C66C300314064 /* Extension.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Extension.m; sourceTree = \"<group>\"; };\n\t\tCDC378C9250C83F100314064 /* Netiquette.app */ = {isa = PBXFileReference; lastKnownFileType = wrapper.application; path = Netiquette.app; sourceTree = \"<group>\"; };\n\t\tCDC41C3F2503424800CB302B /* OrderedDictionary.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OrderedDictionary.m; path = \"3rd-party/OrderedDictionary.m\"; sourceTree = \"<group>\"; };\n\t\tCDC41C402503424800CB302B /* OrderedDictionary.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OrderedDictionary.h; path = \"3rd-party/OrderedDictionary.h\"; sourceTree = \"<group>\"; };\n\t\tCDCAA9662B677AFC00FE27DD /* StartupWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = StartupWindowController.m; sourceTree = \"<group>\"; };\n\t\tCDCAA9672B677AFC00FE27DD /* StartupWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StartupWindowController.h; sourceTree = \"<group>\"; };\n\t\tCDCAA96B2B69DC3700FE27DD /* RulesMenuController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RulesMenuController.m; sourceTree = \"<group>\"; };\n\t\tCDCAA96D2B69DC4500FE27DD /* RulesMenuController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RulesMenuController.h; sourceTree = \"<group>\"; };\n\t\tCDD7853B255609AC001BB0BE /* BlockOrAllowList.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BlockOrAllowList.h; sourceTree = \"<group>\"; };\n\t\tCDD7853C255609AC001BB0BE /* BlockOrAllowList.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BlockOrAllowList.m; sourceTree = \"<group>\"; };\n\t\tCDD992D62C4EC30000A1B406 /* InfoPlist.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = InfoPlist.xcstrings; sourceTree = \"<group>\"; };\n\t\tCDEA3AD02E0724EC00FDD0C0 /* Profiles.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Profiles.h; sourceTree = \"<group>\"; };\n\t\tCDEA3AD12E0724EC00FDD0C0 /* Profiles.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Profiles.m; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\tCDB2CC1524D61A4E00D0EECE /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tCDB2CC4424DBE48100D0EECE /* NetworkExtension.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tCDB2CC2D24D61B3900D0EECE /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tCDA1366F24EF5587005AD424 /* libbsm.tbd in Frameworks */,\n\t\t\t\tCDB2CC3324D61B3900D0EECE /* NetworkExtension.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\tCDA135F824EBB58E005AD424 /* Shared */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tCDA1363A24EF4DA0005AD424 /* consts.h */,\n\t\t\t\tCDA1363824EF4DA0005AD424 /* Rule.h */,\n\t\t\t\tCDA1363724EF4DA0005AD424 /* Rule.m */,\n\t\t\t\tCD21D378252FE91E001A19A8 /* signing.h */,\n\t\t\t\tCD21D379252FE91E001A19A8 /* signing.m */,\n\t\t\t\tCDA1363224EF4DA0005AD424 /* utilities.h */,\n\t\t\t\tCDA1363324EF4DA0005AD424 /* utilities.m */,\n\t\t\t\tCDA1363424EF4DA0005AD424 /* XPCDaemonProto.h */,\n\t\t\t\tCDA1364124EF4DA1005AD424 /* XPCUserProto.h */,\n\t\t\t);\n\t\t\tname = Shared;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tCDA136BD24F0D526005AD424 /* Shared */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tCDA136C624F0D7C3005AD424 /* consts.h */,\n\t\t\t\tCDA136E324F0DA43005AD424 /* Rule.h */,\n\t\t\t\tCDA136E424F0DA43005AD424 /* Rule.m */,\n\t\t\t\tCD21D37C252FE94F001A19A8 /* signing.h */,\n\t\t\t\tCD21D37B252FE94F001A19A8 /* signing.m */,\n\t\t\t\tCDA136C424F0D7C3005AD424 /* utilities.h */,\n\t\t\t\tCDA136C524F0D7C3005AD424 /* utilities.m */,\n\t\t\t);\n\t\t\tname = Shared;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tCDB2CC0F24D61A4E00D0EECE = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tCD0070252C3954220011979F /* Localizable.xcstrings */,\n\t\t\t\tCDB2CC1A24D61A4E00D0EECE /* App */,\n\t\t\t\tCDB2CC3424D61B3900D0EECE /* Extension */,\n\t\t\t\tCDB2CC3124D61B3900D0EECE /* Frameworks */,\n\t\t\t\tCDB2CC1924D61A4E00D0EECE /* Products */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tCDB2CC1924D61A4E00D0EECE /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tCDB2CC1824D61A4E00D0EECE /* LuLu.app */,\n\t\t\t\tCDB2CC3024D61B3900D0EECE /* com.objective-see.lulu.extension.systemextension */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tCDB2CC1A24D61A4E00D0EECE /* App */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tCD2CA1852C3E9E7000D7BEAA /* AboutWindow.xib */,\n\t\t\t\tCDA1369B24F0D2CF005AD424 /* AboutWindowController.h */,\n\t\t\t\tCDA1369524F0D2CF005AD424 /* AboutWindowController.m */,\n\t\t\t\tCD2CA1812C3E9E6C00D7BEAA /* AddRule.xib */,\n\t\t\t\tCDA1369324F0D2CF005AD424 /* AddRuleWindowController.h */,\n\t\t\t\tCDA1369A24F0D2CF005AD424 /* AddRuleWindowController.m */,\n\t\t\t\tCD2CA17D2C3E9E6700D7BEAA /* AlertWindow.xib */,\n\t\t\t\tCDA1367F24F0D268005AD424 /* AlertWindowController.h */,\n\t\t\t\tCDA1367224F0D268005AD424 /* AlertWindowController.m */,\n\t\t\t\tCD2CA18C2C3E9EF200D7BEAA /* App.entitlements */,\n\t\t\t\tCDB2CC1B24D61A4E00D0EECE /* AppDelegate.h */,\n\t\t\t\tCDB2CC1C24D61A4E00D0EECE /* AppDelegate.m */,\n\t\t\t\tCDB2CC1E24D61A5000D0EECE /* Assets.xcassets */,\n\t\t\t\tCDC378C8250C83F100314064 /* Binaries */,\n\t\t\t\tCDB909EC2B72BC2E0043FEB4 /* Configure.h */,\n\t\t\t\tCDB909EA2B72BC230043FEB4 /* Configure.m */,\n\t\t\t\tCDC378C5250C66C200314064 /* Extension.h */,\n\t\t\t\tCDC378C6250C66C300314064 /* Extension.m */,\n\t\t\t\tCDB2CC2324D61A5000D0EECE /* Info.plist */,\n\t\t\t\tCDD992D62C4EC30000A1B406 /* InfoPlist.xcstrings */,\n\t\t\t\tCD2CA1772C3E9E5700D7BEAA /* ItemPaths.xib */,\n\t\t\t\tCD9E147A25171BF200DA05C3 /* ItemPathsWindowController.h */,\n\t\t\t\tCD9E147B25171BF200DA05C3 /* ItemPathsWindowController.m */,\n\t\t\t\tCDB2CC2424D61A5000D0EECE /* main.m */,\n\t\t\t\tCD2CA1902C3E9F0A00D7BEAA /* MainMenu.xib */,\n\t\t\t\tCD9F567D252533CD00F3DEB5 /* NSApplicationKeyEvents.h */,\n\t\t\t\tCD9F567E252533CD00F3DEB5 /* NSApplicationKeyEvents.m */,\n\t\t\t\tCDC41C402503424800CB302B /* OrderedDictionary.h */,\n\t\t\t\tCDC41C3F2503424800CB302B /* OrderedDictionary.m */,\n\t\t\t\tCDA1367A24F0D268005AD424 /* ParentsWindowController.h */,\n\t\t\t\tCDA1367E24F0D268005AD424 /* ParentsWindowController.m */,\n\t\t\t\tCDA1369624F0D2CF005AD424 /* patrons.txt */,\n\t\t\t\tCD2CA1732C3E9E4300D7BEAA /* Preferences.xib */,\n\t\t\t\tCDA1369224F0D2CF005AD424 /* PrefsWindowController.h */,\n\t\t\t\tCDA1368E24F0D2CF005AD424 /* PrefsWindowController.m */,\n\t\t\t\tCDA1369D24F0D2CF005AD424 /* RuleRow.h */,\n\t\t\t\tCDA1369E24F0D2CF005AD424 /* RuleRow.m */,\n\t\t\t\tCD00702F2C3959970011979F /* Rules.xib */,\n\t\t\t\tCDCAA96D2B69DC4500FE27DD /* RulesMenuController.h */,\n\t\t\t\tCDCAA96B2B69DC3700FE27DD /* RulesMenuController.m */,\n\t\t\t\tCDA1368F24F0D2CF005AD424 /* RulesWindowController.h */,\n\t\t\t\tCDA1369C24F0D2CF005AD424 /* RulesWindowController.m */,\n\t\t\t\tCDA136BD24F0D526005AD424 /* Shared */,\n\t\t\t\tCDA1367824F0D268005AD424 /* SigningInfoViewController.h */,\n\t\t\t\tCDA1367524F0D268005AD424 /* SigningInfoViewController.m */,\n\t\t\t\tCDCAA9672B677AFC00FE27DD /* StartupWindowController.h */,\n\t\t\t\tCDCAA9662B677AFC00FE27DD /* StartupWindowController.m */,\n\t\t\t\tCD0070332C39599E0011979F /* StartupWindowController.xib */,\n\t\t\t\tCDA1368224F0D269005AD424 /* StatusBarItem.h */,\n\t\t\t\tCDA1368024F0D268005AD424 /* StatusBarItem.m */,\n\t\t\t\tCD0070372C3959A90011979F /* StatusBarPopover.xib */,\n\t\t\t\tCDA1367724F0D268005AD424 /* StatusBarPopoverController.h */,\n\t\t\t\tCDA1367C24F0D268005AD424 /* StatusBarPopoverController.m */,\n\t\t\t\tCDA136B524F0D4A9005AD424 /* Update.h */,\n\t\t\t\tCDA136B424F0D4A8005AD424 /* Update.m */,\n\t\t\t\tCD00703B2C3959B90011979F /* UpdateWindow.xib */,\n\t\t\t\tCDA136B624F0D4A9005AD424 /* UpdateWindowController.h */,\n\t\t\t\tCDA136B324F0D4A8005AD424 /* UpdateWindowController.m */,\n\t\t\t\tCD00702B2C3956F50011979F /* Welcome.xib */,\n\t\t\t\tCDA1369724F0D2CF005AD424 /* WelcomeWindowController.h */,\n\t\t\t\tCDA1369924F0D2CF005AD424 /* WelcomeWindowController.m */,\n\t\t\t\tCDA136CE24F0D9C1005AD424 /* XPCDaemonClient.h */,\n\t\t\t\tCDA136CF24F0D9C1005AD424 /* XPCDaemonClient.m */,\n\t\t\t\tCDA136CB24F0D94F005AD424 /* XPCUser.h */,\n\t\t\t\tCDA136CC24F0D94F005AD424 /* XPCUser.m */,\n\t\t\t);\n\t\t\tpath = App;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tCDB2CC3124D61B3900D0EECE /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tCDA1366E24EF5587005AD424 /* libbsm.tbd */,\n\t\t\t\tCDB2CC3224D61B3900D0EECE /* NetworkExtension.framework */,\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tCDB2CC3424D61B3900D0EECE /* Extension */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tCDA1365A24EF4E56005AD424 /* Alerts.h */,\n\t\t\t\tCDD7853B255609AC001BB0BE /* BlockOrAllowList.h */,\n\t\t\t\tCDD7853C255609AC001BB0BE /* BlockOrAllowList.m */,\n\t\t\t\tCDA1364F24EF4E56005AD424 /* Alerts.m */,\n\t\t\t\tCD03F8FA24F8E6BD00723BDC /* Binary.h */,\n\t\t\t\tCD03F8F324F8E68300723BDC /* Binary.m */,\n\t\t\t\tCD2CA18B2C3E9ED700D7BEAA /* Extension.entitlements */,\n\t\t\t\tCDB2CC3524D61B3900D0EECE /* FilterDataProvider.h */,\n\t\t\t\tCDB2CC3624D61B3900D0EECE /* FilterDataProvider.m */,\n\t\t\t\tCDA1365D24EF4E57005AD424 /* GrayList.h */,\n\t\t\t\tCDA1365124EF4E56005AD424 /* GrayList.m */,\n\t\t\t\tCDB2CC3A24D61B3900D0EECE /* Info.plist */,\n\t\t\t\tCDA1365024EF4E56005AD424 /* main.h */,\n\t\t\t\tCDB2CC3824D61B3900D0EECE /* main.m */,\n\t\t\t\tCDA1365B24EF4E57005AD424 /* Preferences.h */,\n\t\t\t\tCDA1365324EF4E56005AD424 /* Preferences.m */,\n\t\t\t\tCDEA3AD02E0724EC00FDD0C0 /* Profiles.h */,\n\t\t\t\tCDEA3AD12E0724EC00FDD0C0 /* Profiles.m */,\n\t\t\t\tCD03F8FB24F8E6C600723BDC /* Process.h */,\n\t\t\t\tCD03F8F424F8E68300723BDC /* Process.m */,\n\t\t\t\tCDA1366B24EF4F89005AD424 /* Rules.h */,\n\t\t\t\tCDA1366C24EF4F89005AD424 /* Rules.m */,\n\t\t\t\tCDA135F824EBB58E005AD424 /* Shared */,\n\t\t\t\tCDA1365E24EF4E57005AD424 /* XPCDaemon.h */,\n\t\t\t\tCDA1365624EF4E56005AD424 /* XPCDaemon.m */,\n\t\t\t\tCDA1365C24EF4E57005AD424 /* XPCListener.h */,\n\t\t\t\tCDA1365724EF4E56005AD424 /* XPCListener.m */,\n\t\t\t\tCDA1365924EF4E56005AD424 /* XPCUserClient.h */,\n\t\t\t\tCDA1364D24EF4E56005AD424 /* XPCUserClient.m */,\n\t\t\t);\n\t\t\tpath = Extension;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tCDC378C8250C83F100314064 /* Binaries */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tCDC378C9250C83F100314064 /* Netiquette.app */,\n\t\t\t);\n\t\t\tpath = Binaries;\n\t\t\tsourceTree = SOURCE_ROOT;\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\tCDB2CC1724D61A4E00D0EECE /* LuLu */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = CDB2CC2924D61A5000D0EECE /* Build configuration list for PBXNativeTarget \"LuLu\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tCDB2CC1424D61A4E00D0EECE /* Sources */,\n\t\t\t\tCDB2CC1524D61A4E00D0EECE /* Frameworks */,\n\t\t\t\tCDB2CC1624D61A4E00D0EECE /* Resources */,\n\t\t\t\tCDB2CC4224D61B3900D0EECE /* Embed System Extensions */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\tCDB2CC3D24D61B3900D0EECE /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = LuLu;\n\t\t\tproductName = TestExtension;\n\t\t\tproductReference = CDB2CC1824D61A4E00D0EECE /* LuLu.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n\t\tCDB2CC2F24D61B3900D0EECE /* Extension */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = CDB2CC3F24D61B3900D0EECE /* Build configuration list for PBXNativeTarget \"Extension\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tCDB2CC2C24D61B3900D0EECE /* Sources */,\n\t\t\t\tCDB2CC2D24D61B3900D0EECE /* Frameworks */,\n\t\t\t\tCDB2CC2E24D61B3900D0EECE /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = Extension;\n\t\t\tproductName = Extension;\n\t\t\tproductReference = CDB2CC3024D61B3900D0EECE /* com.objective-see.lulu.extension.systemextension */;\n\t\t\tproductType = \"com.apple.product-type.system-extension\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\tCDB2CC1024D61A4E00D0EECE /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastUpgradeCheck = 1160;\n\t\t\t\tORGANIZATIONNAME = \"Objective-See\";\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\tCDB2CC1724D61A4E00D0EECE = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 11.6;\n\t\t\t\t\t};\n\t\t\t\t\tCDB2CC2F24D61B3900D0EECE = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 11.6;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = CDB2CC1324D61A4E00D0EECE /* Build configuration list for PBXProject \"LuLu\" */;\n\t\t\tcompatibilityVersion = \"Xcode 9.3\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t\tes,\n\t\t\t\tde,\n\t\t\t\tit,\n\t\t\t\tfr,\n\t\t\t\ttr,\n\t\t\t\t\"pt-BR\",\n\t\t\t\tpl,\n\t\t\t\tko,\n\t\t\t\t\"zh-Hant\",\n\t\t\t\tuk,\n\t\t\t\t\"zh-Hans\",\n\t\t\t\tur,\n\t\t\t);\n\t\t\tmainGroup = CDB2CC0F24D61A4E00D0EECE;\n\t\t\tproductRefGroup = CDB2CC1924D61A4E00D0EECE /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\tCDB2CC1724D61A4E00D0EECE /* LuLu */,\n\t\t\t\tCDB2CC2F24D61B3900D0EECE /* Extension */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\tCDB2CC1624D61A4E00D0EECE /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tCD9E04D3254163AF00DB3218 /* patrons.txt in Resources */,\n\t\t\t\tCD0070342C39599E0011979F /* StartupWindowController.xib in Resources */,\n\t\t\t\tCDC378CB250C83F200314064 /* Netiquette.app in Resources */,\n\t\t\t\tCD2CA1782C3E9E5700D7BEAA /* ItemPaths.xib in Resources */,\n\t\t\t\tCD2CA1862C3E9E7000D7BEAA /* AboutWindow.xib in Resources */,\n\t\t\t\tCD00703C2C3959B90011979F /* UpdateWindow.xib in Resources */,\n\t\t\t\tCD2CA1822C3E9E6C00D7BEAA /* AddRule.xib in Resources */,\n\t\t\t\tCD2CA1742C3E9E4300D7BEAA /* Preferences.xib in Resources */,\n\t\t\t\tCD0070302C3959970011979F /* Rules.xib in Resources */,\n\t\t\t\tCD00702C2C3956F50011979F /* Welcome.xib in Resources */,\n\t\t\t\tCD2CA17E2C3E9E6700D7BEAA /* AlertWindow.xib in Resources */,\n\t\t\t\tCD0070262C3954220011979F /* Localizable.xcstrings in Resources */,\n\t\t\t\tCD0070382C3959A90011979F /* StatusBarPopover.xib in Resources */,\n\t\t\t\tCDB2CC1F24D61A5000D0EECE /* Assets.xcassets in Resources */,\n\t\t\t\tCDD992D72C4EC30000A1B406 /* InfoPlist.xcstrings in Resources */,\n\t\t\t\tCD2CA1912C3E9F0A00D7BEAA /* MainMenu.xib in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tCDB2CC2E24D61B3900D0EECE /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tCD0070272C3954220011979F /* Localizable.xcstrings in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\tCDB2CC1424D61A4E00D0EECE /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tCDA136E524F0DA43005AD424 /* Rule.m in Sources */,\n\t\t\t\tCDA136D124F0DA0E005AD424 /* Update.m in Sources */,\n\t\t\t\tCDA136D224F0DA0E005AD424 /* UpdateWindowController.m in Sources */,\n\t\t\t\tCDA136D324F0DA0E005AD424 /* AboutWindowController.m in Sources */,\n\t\t\t\tCDA136D424F0DA0E005AD424 /* AddRuleWindowController.m in Sources */,\n\t\t\t\tCDA136D524F0DA0E005AD424 /* PrefsWindowController.m in Sources */,\n\t\t\t\tCDA136D624F0DA0E005AD424 /* RuleRow.m in Sources */,\n\t\t\t\tCDCAA9692B677AFC00FE27DD /* StartupWindowController.m in Sources */,\n\t\t\t\tCDA136D924F0DA0E005AD424 /* RulesWindowController.m in Sources */,\n\t\t\t\tCDA136DA24F0DA0E005AD424 /* WelcomeWindowController.m in Sources */,\n\t\t\t\tCDA136DB24F0DA0E005AD424 /* AlertWindowController.m in Sources */,\n\t\t\t\tCDA136DD24F0DA0F005AD424 /* ParentsWindowController.m in Sources */,\n\t\t\t\tCDA136DE24F0DA0F005AD424 /* SigningInfoViewController.m in Sources */,\n\t\t\t\tCDA136DF24F0DA0F005AD424 /* StatusBarItem.m in Sources */,\n\t\t\t\tCDA136E024F0DA0F005AD424 /* StatusBarPopoverController.m in Sources */,\n\t\t\t\tCDCAA96C2B69DC3700FE27DD /* RulesMenuController.m in Sources */,\n\t\t\t\tCDA136D024F0D9C1005AD424 /* XPCDaemonClient.m in Sources */,\n\t\t\t\tCD21D37D252FE94F001A19A8 /* signing.m in Sources */,\n\t\t\t\tCDA136C724F0D7C3005AD424 /* utilities.m in Sources */,\n\t\t\t\tCDB2CC2524D61A5000D0EECE /* main.m in Sources */,\n\t\t\t\tCD9E147D25171BF200DA05C3 /* ItemPathsWindowController.m in Sources */,\n\t\t\t\tCDB909EB2B72BC230043FEB4 /* Configure.m in Sources */,\n\t\t\t\tCDB2CC1D24D61A4E00D0EECE /* AppDelegate.m in Sources */,\n\t\t\t\tCD9F567F252533CE00F3DEB5 /* NSApplicationKeyEvents.m in Sources */,\n\t\t\t\tCDC41C412503424800CB302B /* OrderedDictionary.m in Sources */,\n\t\t\t\tCDC378C7250C66C300314064 /* Extension.m in Sources */,\n\t\t\t\tCDA136CD24F0D94F005AD424 /* XPCUser.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tCDB2CC2C24D61B3900D0EECE /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tCDA1364624EF4DA1005AD424 /* utilities.m in Sources */,\n\t\t\t\tCD21D37A252FE91E001A19A8 /* signing.m in Sources */,\n\t\t\t\tCDA1366824EF4E57005AD424 /* XPCListener.m in Sources */,\n\t\t\t\tCDA1364824EF4DA1005AD424 /* Rule.m in Sources */,\n\t\t\t\tCD03F8F624F8E68300723BDC /* Process.m in Sources */,\n\t\t\t\tCDA1366424EF4E57005AD424 /* GrayList.m in Sources */,\n\t\t\t\tCDB2CC3924D61B3900D0EECE /* main.m in Sources */,\n\t\t\t\tCDA1366724EF4E57005AD424 /* XPCDaemon.m in Sources */,\n\t\t\t\tCDA1366324EF4E57005AD424 /* Alerts.m in Sources */,\n\t\t\t\tCDEA3AD22E0724EC00FDD0C0 /* Profiles.m in Sources */,\n\t\t\t\tCDD7853D255609AC001BB0BE /* BlockOrAllowList.m in Sources */,\n\t\t\t\tCDB2CC3724D61B3900D0EECE /* FilterDataProvider.m in Sources */,\n\t\t\t\tCDA1366224EF4E57005AD424 /* XPCUserClient.m in Sources */,\n\t\t\t\tCDA1366D24EF4F89005AD424 /* Rules.m in Sources */,\n\t\t\t\tCDA1366624EF4E57005AD424 /* Preferences.m in Sources */,\n\t\t\t\tCD03F8F524F8E68300723BDC /* Binary.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXTargetDependency section */\n\t\tCDB2CC3D24D61B3900D0EECE /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = CDB2CC2F24D61B3900D0EECE /* Extension */;\n\t\t\ttargetProxy = CDB2CC3C24D61B3900D0EECE /* PBXContainerItemProxy */;\n\t\t};\n/* End PBXTargetDependency section */\n\n/* Begin PBXVariantGroup section */\n\t\tCD00702B2C3956F50011979F /* Welcome.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tCD00702A2C3956F50011979F /* Base */,\n\t\t\t\tCD00702D2C3956F50011979F /* mul */,\n\t\t\t);\n\t\t\tname = Welcome.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tCD00702F2C3959970011979F /* Rules.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tCD00702E2C3959970011979F /* Base */,\n\t\t\t\tCD0070312C3959970011979F /* mul */,\n\t\t\t);\n\t\t\tname = Rules.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tCD0070332C39599E0011979F /* StartupWindowController.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tCD0070322C39599E0011979F /* Base */,\n\t\t\t\tCD0070352C39599E0011979F /* mul */,\n\t\t\t);\n\t\t\tname = StartupWindowController.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tCD0070372C3959A90011979F /* StatusBarPopover.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tCD0070362C3959A90011979F /* Base */,\n\t\t\t\tCD0070392C3959A90011979F /* mul */,\n\t\t\t);\n\t\t\tname = StatusBarPopover.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tCD00703B2C3959B90011979F /* UpdateWindow.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tCD00703A2C3959B90011979F /* Base */,\n\t\t\t\tCD00703D2C3959B90011979F /* mul */,\n\t\t\t);\n\t\t\tname = UpdateWindow.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tCD2CA1732C3E9E4300D7BEAA /* Preferences.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tCD2CA1722C3E9E4300D7BEAA /* Base */,\n\t\t\t\tCD2CA1752C3E9E4300D7BEAA /* mul */,\n\t\t\t);\n\t\t\tname = Preferences.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tCD2CA1772C3E9E5700D7BEAA /* ItemPaths.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tCD2CA1762C3E9E5700D7BEAA /* Base */,\n\t\t\t\tCD2CA1792C3E9E5700D7BEAA /* mul */,\n\t\t\t);\n\t\t\tname = ItemPaths.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tCD2CA17D2C3E9E6700D7BEAA /* AlertWindow.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tCD2CA17C2C3E9E6700D7BEAA /* Base */,\n\t\t\t\tCD2CA17F2C3E9E6700D7BEAA /* mul */,\n\t\t\t);\n\t\t\tname = AlertWindow.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tCD2CA1812C3E9E6C00D7BEAA /* AddRule.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tCD2CA1802C3E9E6C00D7BEAA /* Base */,\n\t\t\t\tCD2CA1832C3E9E6C00D7BEAA /* mul */,\n\t\t\t);\n\t\t\tname = AddRule.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tCD2CA1852C3E9E7000D7BEAA /* AboutWindow.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tCD2CA1842C3E9E7000D7BEAA /* Base */,\n\t\t\t\tCD2CA1872C3E9E7000D7BEAA /* mul */,\n\t\t\t);\n\t\t\tname = AboutWindow.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tCD2CA18B2C3E9ED700D7BEAA /* Extension.entitlements */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tCD2CA18A2C3E9ED700D7BEAA /* Base */,\n\t\t\t);\n\t\t\tname = Extension.entitlements;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tCD2CA1902C3E9F0A00D7BEAA /* MainMenu.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tCD2CA18F2C3E9F0A00D7BEAA /* Base */,\n\t\t\t\tCD2CA1922C3E9F0A00D7BEAA /* mul */,\n\t\t\t);\n\t\t\tname = MainMenu.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\tCDB2CC2724D61A5000D0EECE /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++14\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tLOCALIZATION_PREFERS_STRING_CATALOGS = YES;\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.15;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = macosx;\n\t\t\t\tSWIFT_EMIT_LOC_STRINGS = YES;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tCDB2CC2824D61A5000D0EECE /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++14\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tLOCALIZATION_PREFERS_STRING_CATALOGS = YES;\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.15;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tSDKROOT = macosx;\n\t\t\t\tSWIFT_EMIT_LOC_STRINGS = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tCDB2CC2A24D61A5000D0EECE /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCODE_SIGN_ENTITLEMENTS = App/App.entitlements;\n\t\t\t\tCODE_SIGN_IDENTITY = \"Developer ID Application\";\n\t\t\t\tCODE_SIGN_STYLE = Manual;\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tCURRENT_PROJECT_VERSION = 4.3.1;\n\t\t\t\tDEVELOPMENT_TEAM = VBG97UB4TA;\n\t\t\t\t\"DEVELOPMENT_TEAM[sdk=macosx*]\" = VBG97UB4TA;\n\t\t\t\tENABLE_HARDENED_RUNTIME = YES;\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = \"\";\n\t\t\t\tINFOPLIST_FILE = App/Info.plist;\n\t\t\t\tINFOPLIST_KEY_LSApplicationCategoryType = \"public.app-category.utilities\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/../Frameworks\",\n\t\t\t\t);\n\t\t\t\tLOCALIZATION_PREFERS_STRING_CATALOGS = YES;\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.15;\n\t\t\t\tMARKETING_VERSION = 4.3.1;\n\t\t\t\tONLY_ACTIVE_ARCH = NO;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.objective-see.lulu.app\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"LuLu Application\";\n\t\t\t\t\"PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]\" = \"LuLu Application\";\n\t\t\t\tSWIFT_EMIT_LOC_STRINGS = YES;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tCDB2CC2B24D61A5000D0EECE /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCODE_SIGN_ENTITLEMENTS = App/App.entitlements;\n\t\t\t\tCODE_SIGN_IDENTITY = \"Developer ID Application\";\n\t\t\t\tCODE_SIGN_STYLE = Manual;\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tCURRENT_PROJECT_VERSION = 4.3.1;\n\t\t\t\tDEVELOPMENT_TEAM = VBG97UB4TA;\n\t\t\t\t\"DEVELOPMENT_TEAM[sdk=macosx*]\" = VBG97UB4TA;\n\t\t\t\tENABLE_HARDENED_RUNTIME = YES;\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = \"\";\n\t\t\t\tINFOPLIST_FILE = App/Info.plist;\n\t\t\t\tINFOPLIST_KEY_LSApplicationCategoryType = \"public.app-category.utilities\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/../Frameworks\",\n\t\t\t\t);\n\t\t\t\tLOCALIZATION_PREFERS_STRING_CATALOGS = YES;\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.15;\n\t\t\t\tMARKETING_VERSION = 4.3.1;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.objective-see.lulu.app\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"LuLu Application\";\n\t\t\t\t\"PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]\" = \"LuLu Application\";\n\t\t\t\tSWIFT_EMIT_LOC_STRINGS = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tCDB2CC4024D61B3900D0EECE /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCODE_SIGN_ENTITLEMENTS = Extension/Extension.entitlements;\n\t\t\t\tCODE_SIGN_IDENTITY = \"Apple Development\";\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=macosx*]\" = \"Developer ID Application\";\n\t\t\t\tCODE_SIGN_STYLE = Manual;\n\t\t\t\tCURRENT_PROJECT_VERSION = 4.3.1;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\t\"DEVELOPMENT_TEAM[sdk=macosx*]\" = VBG97UB4TA;\n\t\t\t\tENABLE_HARDENED_RUNTIME = YES;\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = \"\";\n\t\t\t\tINFOPLIST_FILE = Extension/Info.plist;\n\t\t\t\tINFOPLIST_KEY_CFBundleDisplayName = \"LuLu Network Extension\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/../Frameworks\",\n\t\t\t\t\t\"@executable_path/../../../../Frameworks\",\n\t\t\t\t);\n\t\t\t\tLIBRARY_SEARCH_PATHS = \"\";\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.15;\n\t\t\t\tMARKETING_VERSION = 4.3.1;\n\t\t\t\tONLY_ACTIVE_ARCH = NO;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.objective-see.lulu.extension\";\n\t\t\t\tPRODUCT_NAME = \"com.objective-see.lulu.extension\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\t\"PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]\" = \"LuLu Extension\";\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tCDB2CC4124D61B3900D0EECE /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCODE_SIGN_ENTITLEMENTS = Extension/Extension.entitlements;\n\t\t\t\tCODE_SIGN_IDENTITY = \"Apple Development\";\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=macosx*]\" = \"Developer ID Application\";\n\t\t\t\tCODE_SIGN_STYLE = Manual;\n\t\t\t\tCURRENT_PROJECT_VERSION = 4.3.1;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\t\"DEVELOPMENT_TEAM[sdk=macosx*]\" = VBG97UB4TA;\n\t\t\t\tENABLE_HARDENED_RUNTIME = YES;\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = \"\";\n\t\t\t\tINFOPLIST_FILE = Extension/Info.plist;\n\t\t\t\tINFOPLIST_KEY_CFBundleDisplayName = \"LuLu Network Extension\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/../Frameworks\",\n\t\t\t\t\t\"@executable_path/../../../../Frameworks\",\n\t\t\t\t);\n\t\t\t\tLIBRARY_SEARCH_PATHS = \"\";\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.15;\n\t\t\t\tMARKETING_VERSION = 4.3.1;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.objective-see.lulu.extension\";\n\t\t\t\tPRODUCT_NAME = \"com.objective-see.lulu.extension\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\t\"PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]\" = \"LuLu Extension\";\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\tCDB2CC1324D61A4E00D0EECE /* Build configuration list for PBXProject \"LuLu\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tCDB2CC2724D61A5000D0EECE /* Debug */,\n\t\t\t\tCDB2CC2824D61A5000D0EECE /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tCDB2CC2924D61A5000D0EECE /* Build configuration list for PBXNativeTarget \"LuLu\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tCDB2CC2A24D61A5000D0EECE /* Debug */,\n\t\t\t\tCDB2CC2B24D61A5000D0EECE /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tCDB2CC3F24D61B3900D0EECE /* Build configuration list for PBXNativeTarget \"Extension\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tCDB2CC4024D61B3900D0EECE /* Debug */,\n\t\t\t\tCDB2CC4124D61B3900D0EECE /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = CDB2CC1024D61A4E00D0EECE /* Project object */;\n}\n"
  },
  {
    "path": "LuLu/LuLu.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <Group\n      location = \"container:\"\n      name = \"New Group\">\n      <Group\n         location = \"group:\"\n         name = \"Uninstaller\">\n      </Group>\n   </Group>\n   <FileRef\n      location = \"self:\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": "LuLu/LuLu.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>IDEDidComputeMac32BitWarning</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "LuLu/LuLu.xcodeproj/xcshareddata/xcschemes/Extension.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1160\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"NO\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"8D1107260486CEB800E47090\"\n               BuildableName = \"LuLu Uninstaller.app\"\n               BlueprintName = \"Uninstaller\"\n               ReferencedContainer = \"container:../Uninstaller/Uninstaller.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"CDB2CC1724D61A4E00D0EECE\"\n               BuildableName = \"LuLu.app\"\n               BlueprintName = \"LuLu\"\n               ReferencedContainer = \"container:LuLu.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <Testables>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "LuLu/LuLu.xcodeproj/xcshareddata/xcschemes/LuLu.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1160\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"NO\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"CDB2CC1724D61A4E00D0EECE\"\n               BuildableName = \"LuLu.app\"\n               BlueprintName = \"LuLu\"\n               ReferencedContainer = \"container:LuLu.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <Testables>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"CDB2CC1724D61A4E00D0EECE\"\n            BuildableName = \"LuLu.app\"\n            BlueprintName = \"LuLu\"\n            ReferencedContainer = \"container:LuLu.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"CDB2CC1724D61A4E00D0EECE\"\n            BuildableName = \"LuLu.app\"\n            BlueprintName = \"LuLu\"\n            ReferencedContainer = \"container:LuLu.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "LuLu/Shared/Localizable.xcstrings",
    "content": "{\n  \"sourceLanguage\" : \"en\",\n  \"strings\" : {\n    \" has a signing issue\" : {\n      \"comment\" : \" has a signing issue\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \" hat ein Signaturproblem\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"tiene un problema de firma\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"a un problème de signature\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ha un problema con la firma\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"의 서명에 문제가 있음\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ma problem z podpisem\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"tem um problema de assinatura\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \" için imzalama sorunu var\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"має проблему з підписом\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \" دستخط کا مسئلہ ہے\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"存在签名问题\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"存在簽章問題\"\n          }\n        }\n      }\n    },\n    \" is not signed\" : {\n      \"comment\" : \" is not signed\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \" ist nicht signiert\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"no está firmado\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"n’est pas signé\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"non è firmato\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"은(는) 서명되지 않음\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"nie jest podpisany\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"não possui assinatura\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \" imzalı değil\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"не підписано\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \" دستخط شدہ نہیں ہے\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"未签名\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"沒有簽章\"\n          }\n        }\n      }\n    },\n    \" is not validly signed\" : {\n      \"comment\" : \" is not validly signed\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \" ist nicht gültig signiert\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"no está válidamente firmado\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"n’est pas valablement signé\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"non ha una firma valida\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"의 서명은 유효하지 않음\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"nie jest podpisany prawidłowo\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"não possui assinatura válida\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \" geçerli bir biçimde imzalanmamış\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"підпис недійсний\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \" درست طریقے سے دستخط شدہ نہیں ہے\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"没有有效的签名\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"沒有有效的簽章\"\n          }\n        }\n      }\n    },\n    \" is validly signed\" : {\n      \"comment\" : \" is validly signed\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \" ist gültig signiert\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"válidamente firmado\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"est valablement signé\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ha una firma valida\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"의 서명은 유효함\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"jest prawidłowo podpisany\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"possui assinatura válida\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \" geçerli bir biçimde imzalanmış\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"успішно підписано\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \" درست طریقے سے دستخط شدہ ہے\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"具有有效的签名\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"具有有效的簽章\"\n          }\n        }\n      }\n    },\n    \" unknown\" : {\n      \"comment\" : \" unknown\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \" unbekannt\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"desconocido\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"inconnu\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"sconosciuto\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \" 알 수 없음\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"nieznany\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"desconhecido\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \" bilinmiyor\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"невідомий\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \" نامعلوم\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"未知\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"未知\"\n          }\n        }\n      }\n    },\n    \"...please copy it into /Applications and re-launch.\" : {\n      \"comment\" : \"...please copy it into /Applications and re-launch.\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"…bitte kopieren Sie es in /Applications und starten Sie die Anwendung neu.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"…por favor, cópielo en /Applications y reinicie la aplicación.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"…veuillez le copier dans /Applications et relancer l'application.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"…si prega di copiarlo in /Applications e riavviare l'applicazione.\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"…/Applications에 복사한 후 다시 실행해 주세요.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"…proszę skopiować do /Applications i ponownie uruchomić aplikację.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"…por favor, copie para /Applications e reinicie o aplicativo.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"…lütfen /Applications klasörüne kopyalayın ve uygulamayı yeniden başlatın.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"…будь ласка, скопіюйте до /Applications та перезапустіть програму.\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"…براہ کرم اسے /Applications میں کاپی کریں اور ایپلیکیشن دوبارہ شروع کریں۔\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"…请将其复制到 /Applications 中并重新启动。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"…請將其複製到 /Applications 中並重新啟動。\"\n          }\n        }\n      }\n    },\n    \"...this will fully remove LuLu from your Mac\" : {\n      \"comment\" : \"...this will fully remove LuLu from your Mac\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"...das wird LuLu vollständig von deinem Mac entfernen.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"...esto eliminará completamente LuLu de tu Mac\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"… ceci retirera Lulu complètement de votre Mac\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"…questo rimuoverà completamente LuLu dal tuo Mac\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"...이 작업은 사용자의 Mac에서 LuLu를 완전히 삭제합니다.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"...spowoduje to całkowite usunięcie LuLu z Twojego Maca\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"…isto vai remover LuLu completamente do seu Mac\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"…bu, LuLu’yu Mac’inizden tümüyle kaldıracaktır\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"…це повністю видалить LuLu з вашого Маку\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"...یہ آپ کے میک سے لولو کو مکمل طور پر ہٹا دے گا\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"…这会将LuLu从您的Mac完全移除。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"…這會將 LuLu 從您的 Mac 完全移除 。\"\n          }\n        }\n      }\n    },\n    \"...this will terminate LuLu, until the next time you log in.\" : {\n      \"comment\" : \"...this will terminate LuLu, until the next time you log in.\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"...das wird LuLu beenden, bis du dich das nächste Mal anmeldest.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"...esto terminará LuLu, hasta la próxima vez que inicies sesión.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"… cela arrêtera LuLu, jusqu'à la prochaine ouverture de session.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"…questo arresterà LuLu, fino al prossimo accesso\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"...이 작업은 다음 로그인할 때까지 LuLu의 작동을 멈춥니다.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"...spowoduje to zamknięcie LuLu, do czasu ponownego zalogowania.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"…isto vai encerrar LuLu, até o próximo login.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"…bu, bir sonraki oturum açışınıza dek LuLu’yu sonlandıracaktır\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"…це зупинить роботу LuLu до наступного входу.\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"...یہ آپ کے اگلے لاگ ان تک لولو کو ختم کر دے گا۔\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"…这将关闭LuLu 直到您下次登入\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"…這將關閉 LuLu，直到您下次登入。\"\n          }\n        }\n      }\n    },\n    \"'%@' matches an existing profile name.\" : {\n      \"comment\" : \"'%@' matches an existing profile name.\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"„%@“ stimmt mit einem vorhandenen Profilnamen überein.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"“%@” coincide con un nombre de perfil existente.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"« %@ » correspond à un nom de profil existant.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"\\\"%@\\\" corrisponde a un nome di profilo esistente.\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"\\\"%@\\\"은(는) 기존 프로필 이름과 일치합니다.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"„%@” pasuje do istniejącej nazwy profilu.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"“%@” corresponde a um nome de perfil existente.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"“%@” var olan bir profil adıyla eşleşiyor.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"«%@» збігається з існуючою назвою профілю.\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"'%@' کسی موجودہ پروفائل نام سے میل کھاتا ہے۔\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"“%@” 与现有的配置文件名称匹配。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"“%@” 与现有配置文件名称匹配。\"\n          }\n        }\n      }\n    },\n    \"'Default' is a reserved profile name.\" : {\n      \"comment\" : \"'Default' is a reserved profile name.\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"„Default“ ist ein reservierter Profilname.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"“Default” es un nombre de perfil reservado.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"« Default » est un nom de profil réservé.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"\\\"Default\\\" è un nome di profilo riservato.\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"\\\"Default\\\"은 예약된 프로필 이름입니다.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"„Default” jest zastrzeżoną nazwą profilu.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"“Default” é um nome de perfil reservado.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"“Saptanmış”, ayrılmış bir profil adıdır.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"«Default» — зарезервована назва профілю.\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"'Default' ایک محفوظ شدہ پروفائل نام ہے۔\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"“Default” 是保留的配置文件名称。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"“Default”是保留的配置文件名称。\"\n          }\n        }\n      }\n    },\n    \"› no signing authorities\" : {\n      \"comment\" : \"› no signing authorities\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"› keine Zertifizierungsinstanz\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"› no hay autoridades de firma\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"> pas d’autorité de signature\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"› non firmato\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"› 인증 기관 없음\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"> brak upoważnień do podpisywania\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"> sem autoridades de assinatura\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"› imzalama otoritesi yok\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"› немає довірених підписантів\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"› دستخط کرنے والے اتھارٹی نہیں ہیں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"没有签名权限\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"› 無簽署單位\"\n          }\n        }\n      }\n    },\n    \"%@ (pid: %@)\" : {\n      \"comment\" : \"%@ (pid: %@)\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ (pid: %2$@)\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"%1$@ (pid: %2$@)\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ (pid: %2$@)\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ (pid : %2$@)\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (pid: %@)\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ (pid: %2$@)\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ (pid: %2$@)\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ (pid: %2$@)\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ (pid: %2$@)\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ (PID: %2$@) \"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ (پی ڈی: %2$@)\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (pid: %@)\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@（pid: %@）\"\n          }\n        }\n      }\n    },\n    \"%@ (signer: %@)\" : {\n      \"comment\" : \"%@ (signer: %@)\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ (Unterzeichner: %2$@)\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"%1$@ (signer: %2$@)\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ (firmante: %2$@)\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ (signataire : %2$@)\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ (firmato da: %2$@)\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ (서명자: %2$@)\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ (sygnatariusz: %2$@)\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ (assinante: %2$@)\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ (imzalayan: %2$@)\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ (підписант: %2$@) \"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ (دستخط کنندہ: %2$@)\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@（签名者：%@）\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (簽署者：%@）\"\n          }\n        }\n      }\n    },\n    \"%@ (signer: Apple Mac OS App Store)\" : {\n      \"comment\" : \"%@ (signer: Apple Mac OS App Store)\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (Unterzeichner: Apple Mac OS App Store)\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (firmante: Apple Mac OS App Store)\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (signataire : Apple Mac OS App Store)\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (firmato da: Apple Mac OS App Store)\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (서명자: Apple Mac OS App Store)\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (sygnatariusz: Sklep Aplikacji Apple Mac OS)\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (assinante: Apple Mac OS App Store)\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (imzalayan: Apple macOS App Store)\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (підписант: Apple Mac OS App Store)\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (دستخط کنندہ: ایپل میک او ایس ایپ اسٹور)\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@（签名者：Apple Mac OS App Store）\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@（簽署者：Apple Mac OS App Store）\"\n          }\n        }\n      }\n    },\n    \"%@ (signer: Apple Proper)\" : {\n      \"comment\" : \"%@ (signer: Apple Proper)\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (Unterzeichner: Apple selbst)\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (firmante: Apple Original)\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (signataire : Apple)\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (firmato da: Apple Proper)\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (서명자: Apple 자체 서명)\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (sygnatariusz: firma Apple)\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (assinante: a própria Apple)\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (imzalayan: Apple)\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (підписант: Apple Proper)\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (دستخط کنندہ: ایپل پروپر)\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@（签名者：Apple Proper）\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@（簽署者：Apple Proper）\"\n          }\n        }\n      }\n    },\n    \"%@ (signer: invalid/unsigned)\" : {\n      \"comment\" : \"%@ (signer: invalid/unsigned)\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (Unterzeichner: ungültig/unsigniert)\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (firmante: no válido/no firmado)\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (signataire : invalide/non signé)\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (firmato da: Non Valido/Non Firmato)\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (서명자: 유효하지 않음/서명되지 않음)\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (sygnatariusz: nieprawidłowy/nieprzypisany)\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (assinante: inválido/sem assinatura)\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (imzalayan: Geçersiz/İmzasız)\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (підписант: невалідний/не підписано)\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (دستخط کنندہ: غیر معتبر/غیر دستخط شدہ)\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@（签名者：无效/未签名）\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@（簽署者：無效／未簽署）\"\n          }\n        }\n      }\n    },\n    \"%@ does not exist!\" : {\n      \"comment\" : \"%@ does not exist!\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ existiert nicht!\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ no existe!\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ n'existe pas !\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ non esiste!\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@은(는) 존재하지 않습니다!\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ nie istnieje!\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ não existe!\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ yok!\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ не існує!\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ موجود نہیں ہے!\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ 不存在！\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ 不存在！\"\n          }\n        }\n      }\n    },\n    \"%@ is legitimate macOS process\" : {\n      \"comment\" : \"%@ is legitimate macOS process\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ ist ein legitimer macOS-Prozess\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ es un proceso legítimo de macOS \"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ est un processus macOS légitime\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ è un processo legittimo di macOS\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@은(는) 적법한 macOS 프로세스입니다\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ jest prawidłowym procesem macOS\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ é um processo legítimo do macOS\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ geçerli bir macOS işlemi\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ є легітимним процесом macOS\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ ایک قانونی میکس او ایس پروسس ہے\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@是合法的macOS程序\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ 是合法的 macOS 程式\"\n          }\n        }\n      }\n    },\n    \"%@ is not a valid (port) number\" : {\n      \"comment\" : \"%@ is not a valid (port) number\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ ist keine gültige (Port-)Nummer\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ no es un número válido (de puerto)\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ n'est un numéro (de port) valide\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ non è un numero (di porta) valido\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@은(는) 유효하지 않은 (포트) 번호입니다\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ nie jest prawidłowym numerem (portu)\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ não é um número (de porta) válido \"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ geçerli bir kapı numarası değil\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ не є валідним номером порту\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ ایک درست (پورٹ) نمبر نہیں ہے\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ 不是有效的（端口）号\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ 不是有效的（連接埠）號碼\"\n          }\n        }\n      }\n    },\n    \"%@ is not a valid regular expression\\r\\ndetails: %@\" : {\n      \"comment\" : \"%@ is not a valid regular expression\\r\\ndetails: %@\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ ist kein gültiger regulärer Ausdruck\\r\\nDetails: %2$@\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"%1$@ is not a valid regular expression\\r\\ndetails: %2$@\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ no es una expresión regular válida\\r\\ndetalles: %2$@\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ n’est pas une expression régulière valide\\ndetails : %2$@\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ non è un’espressione regolare valida\\ndettagli: %@\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@은(는) 유효하지 않는 정규 표현식입니다\\n세부 정보: %2$@\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ nie jest prawidłowym wyrażeniem regularnym szczegóły: %2$@\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ não é uma expressão regular válida. Detalhes: %2$@\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ geçerli bir düzenli ifade değil, ayrıntılar: %2$@\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ не є валідним регулярним виразом  \\nДеталі: %2$@\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ ایک درست ریگولر ایکسپریشن نہیں ہے\\nتفصیلات: %2$@\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ 不是有效的正则表达式\\n详细信息：%@\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ 不是有效的正則表達式\\n詳細資訊：%2$@\"\n          }\n        }\n      }\n    },\n    \"%@ signed by 3rd-party/ad hoc\" : {\n      \"comment\" : \"%@ signed by 3rd-party/ad hoc\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ von Drittanbieter/ad hoc signiert\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ firmado por un tercero/ad hoc\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ signé par une tierce-partie/ad hoc\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ è firmato da \"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ 은(는) 서드파티/Ad hoc 서명됨\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ podpisane przez stronę trzecią/doraźnie\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ assinado por terceiros/ad hoc\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ 3. kişiler/geçici kişi tarafından imzalanmış\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ має неофіційний (ad hoc) підпис\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ تیسری پارٹی/ایڈ ہاک کے ذریعہ دستخط شدہ ہے\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ 由第三方/临时签名\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ 由第三方／臨時簽署\"\n          }\n        }\n      }\n    },\n    \"%@ signed by Apple proper\" : {\n      \"comment\" : \"%@ signed by Apple proper\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ signiert von Apple selbst\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ firmado por Apple oficialmente\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ signé par Apple\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ firmato correttamente da Apple\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ Apple에 의해 자체 서명됨\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ podpisane przez firmę Apple\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ assinado pela própria Apple\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ Apple tarafından düzgünce imzalanmış\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ підписано безпосередньо Apple\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ ایپل پروپر کے ذریعہ دستخط شدہ ہے\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ 由 Apple 正式签名\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ 由 Apple Proper 簽署\"\n          }\n        }\n      }\n    },\n    \"%@ signed by Mac App Store\" : {\n      \"comment\" : \"%@ signed by Mac App Store\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ signiert vom Mac App Store\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ firmado por Mac App store\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ signé par le Mac App Store\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ firmato da Mac App Store\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ Mac App Store에 의해 서명됨\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ podpisane przez Mac App Store\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ assinado pela App Store no Mac\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ Mac App Store tarafından imzalanmış\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ підписано Mac App Store\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ میک ایپ اسٹور کے ذریعہ دستخط شدہ ہے\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ 由 Mac App Store 签名\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ 由 Mac App Store 簽署\"\n          }\n        }\n      }\n    },\n    \"%@ signed with an Apple Developer ID\" : {\n      \"comment\" : \"%@ signed with an Apple Developer ID\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ signiert mit einer Apple Developer ID\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ firmado con un ID de Desarrollador de Apple\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ signé avec un Apple Developer ID\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ firmato da un Apple Developer ID\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ Apple Developer ID에 의해 서명됨\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ podpisano za pomocą Apple Developer ID\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ assinado com ID de Desenvolvidor Apple\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ bir Apple Geliştirici Kimliği ile imzalanmış\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ підписано з Apple Developer ID\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ ایپل ڈویلپر آئی ڈی کے ذریعہ دستخط شدہ ہے\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ 使用 Apple 开发者 ID 签名\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ 由 Apple 開發者 ID 簽署\"\n          }\n        }\n      }\n    },\n    \"%@ signing error: %#lx\" : {\n      \"comment\" : \"%@ signing error: %#lx\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ Signaturfehler: %#lx\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ error de firma: %#lx\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ erreur de signature : %#lx\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ errore di firma: %#lx\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ 서명 에러: %#lx\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ błąd podpisywania: %#lx\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ erro de assinatura: %#lx\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ imzalama hatası: %#lx\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"помилка підпису: %#lx\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ دستخطی خطا: %#lx\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ 签名错误：%#lx\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ 簽署錯誤：%#lx\"\n          }\n        }\n      }\n    },\n    \"%@ this rule, may impact legitimate system functionalty ...continue?\" : {\n      \"comment\" : \"%@ this rule, may impact legitimate system functionalty ...continue?\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ diese Regel könnte die legitime Systemfunktionalität beeinträchtigen ...fortfahren?\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ esta regla, puede impactar la funcionalidad legítima del sistema...¿continuar?\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ cette règle, peut impacter le fonctionnement légitime du système ... continuer ?\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ questa regola potrebbe impattare alcune funzionalità di sistema ...continuare?\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ 작업 시, 적법한 시스템 기능에 영향이 있을 수 있습니다. 계속할까요?\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ ta reguła, może mieć wpływ na prawidłowe funkcjonowanie systemu...kontynuować?\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ esta regra, pode impactar funcionalidade legítima do sistema …prosseguir?\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"bu kuralı %@ yapmak, geçerli sistem işlevselliğini etkileyebilir …sürdürülsün mü?\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ це правило може вплинути на коректну роботу системи... Продовжити?\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ اس قاعدہ سے، قانونی سسٹم کی کارکردگی پر اثر پڑ سکتا ہے ... جاری رکھیں؟\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ 此规则可能会影响合法系统功能…要继续吗？\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ 此規則可能影響系統的正常功能…要繼續嗎？\"\n          }\n        }\n      }\n    },\n    \"%@'s code signing information has changed\" : {\n      \"comment\" : \"%@'s code signing information has changed\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@s Codesignierungsinformationen haben sich geändert.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"la información de firma de código de %@ ha cambiado\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Les informations de signature de %@ ont changé\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"La firma di %@ è cambiata\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@의 디지털 서명 정보가 변경되었습니다\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ Informacje o podpisie kodu uległy zmianie\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \" %@ teve mudanças na informação da sua assinatura de código\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ öğesinin kod imzalama bilgisi değiştirildi\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Інформація щодо підпису коду %@ змінилася\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ کی کوڈ دستخط کی معلومات تبدیل ہو گئی ہیں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ 的代码签名信息已发生改变\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ 的程式簽署資訊已變更\"\n          }\n        }\n      }\n    },\n    \"<unknown (%d)>\" : {\n      \"comment\" : \"<unknown (%d)>\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"<unbekannt (%d)>\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"<desconocido (%d)>\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"<(%d) inconnu>\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"<sconosciuto (%d)>\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"<알 수 없음 (%d)>\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"<nieznany (%d)>\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"<desconhecido (%d)>\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"<bilinmeyen (%d)>\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"<невідомий (%d)>\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"<نامعلوم (%d)>\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"<未知（%d）>\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"<unknown (%d)>\"\n          }\n        }\n      }\n    },\n    \"2. In System Settings, scroll to where it mentions 'LuLu' and click 'Allow'\" : {\n      \"comment\" : \"2. In System Settings, scroll to where it mentions 'LuLu' and click 'Allow'\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"2. Scrolle in den Systemeinstellungen zu der Stelle, an der „LuLu“ erwähnt wird und klicke auf „Erlauben“.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"2. En Configuración del Sistema, deslice hasta 'LuLu' y haga click en 'Permitir'\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"2. Dans Réglages Systèmes, descendez jusqu’à 'LuLu' et cliquez sur 'Approuver'\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"2. Nelle Impostazioni di Sistema, scorri fino alla voce “LuLu” e clicca su “Consenti”\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"2. 시스템 설정에서 'LuLu'가 있는 곳으로 스크롤하여 '허용'을 클릭합니다\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"2. W Ustawieniach systemowych przewiń do miejsca, w którym wspomniano o „LuLu” i kliknij „Zezwól”\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"2. Nas Preferências do Sistema, role até encontrar ‘LuLu’ e clique em ‘Permitir’\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"2. Sistem Ayarları’nda, “LuLu”dan söz ettiği yere sarın ve “İzin Ver”e tıklayın\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"2. У «Системних параметрах» прокрутіть до LuLu і натисніть «Дозволити».\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"2. سسٹم سیٹنگز میں، 'LuLu' کے ذکر کردہ مقام پر اسکرول کریں اور 'الاؤ' پر کلک کریں۔\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"2. 在系统设置中，滚动到提到“LuLu”的位置，然后单击“允许”\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"2. 在「系統設定」中，捲動至提及「LuLu」的部分，然後點擊「允許」\"\n          }\n        }\n      }\n    },\n    \"2. In System Settings, toggle on the LuLu extension\" : {\n      \"comment\" : \"2. In System Settings, toggle on the LuLu extension\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"2. Schalte die LuLu-Erweiterung in den Systemeinstellungen ein.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"2. En Configuración del Sistema, active la extensión de Lulu\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"2. Dans Réglages Systèmes, activer l’extension LuLu\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"2. Nelle Impostazioni di Sistema, abilita l’estensione LuLu\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"2. 시스템 설정에서 LuLu 확장 프로그램을 켭니다\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"2. W Ustawieniach systemowych włącz rozszerzenie LuLu\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"2. Nas Preferências do Sistema, clique na extensão do LuLu\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"2. Sistem Ayarları’nda, LuLu genişletmesini açın\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"2. У «Системних параметрах» увімкніть розширення LuLu.\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"2. سسٹم سیٹنگز میں، LuLu ایکسٹینشن کو آن کریں۔\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"2. 在系统设置中，打开 LuLu 扩展程序\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"2. 在「系統設定」中，開啟 LuLu 延伸功能\"\n          }\n        }\n      }\n    },\n    \"a new version (%@) is available!\" : {\n      \"comment\" : \"a new version (%@) is available!\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"eine neue Version (%@) ist verfügbar!\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"¡una nueva versión (%@) está disponible!\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"une nouvelle version (%@) est disponible !\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"una nuova versione (%@) è disponibile!\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"새로운 버전(%@)이 있습니다!\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"dostępna jest nowa wersja (%@)!\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"uma nova versão (%@) está disponível!\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"yeni bir sürüm (%@) kullanılabilir!\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"доступна нова версія (%@)!\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ایک نئی ورژن (%@) دستیاب ہے!\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"有新版本（%@）可用！\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"有可用的新版本（%@）！\"\n          }\n        }\n      }\n    },\n    \"Ad hoc\" : {\n      \"comment\" : \"Ad hoc\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ad hoc\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ad hoc\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ad hoc\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"A questo\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ad hoc\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Doraźnie\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ad Hoc\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Geçici\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ad hoc\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ایڈ ہاک\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"临时签名\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"臨時簽署\"\n          }\n        }\n      }\n    },\n    \"Add Profile\" : {\n      \"comment\" : \"Add Profile\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profil hinzufügen\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Agregar perfil\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ajouter un profil\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aggiungi profilo\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"프로필 추가\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dodaj profil\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Adicionar perfil\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profil Ekle\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Додати профіль\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"پروفائل شامل کریں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"添加配置文件\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"添加配置文件\"\n          }\n        }\n      }\n    },\n    \"Added in last 24 hours (sorted by creation time)\" : {\n      \"comment\" : \"Added in last 24 hours (sorted by creation time)\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"In den letzten 24 Stunden hinzugefügt (nach Erstellungszeit sortiert)\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Agregado en las últimas 24 horas (ordenado por hora de creación)\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ajoutés ces dernières 24 heures (trié par date de création)\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aggiunte nelle ultime 24 ore (ordinate per data di creazione)\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"최근 24시간 이내에 추가됨 (생성 시간 순 정렬)\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dodano w ciągu ostatnich 24 godzin (posortowane według czasu utworzenia)\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Adicionado nas últimas 24h (ordenados por hora de criação)\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Son 24 saat içinde eklendi (oluşturulma zamanına göre sıralı)\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \" Додано за останні 24 години (відсортовано за часом створення)\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"گذشتہ 24 گھنٹوں میں شامل کیا گیا (تخلیق کے وقت کے مطابق ترتیب دیا گیا)\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"过去 24 小时内添加（按创建时间排序）\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"過去 24 小時內新增（依建立時間排序）\"\n          }\n        }\n      }\n    },\n    \"Added passively (either if 'passive mode' is set, or no user was logged in when rule was created)\" : {\n      \"comment\" : \"Added passively (either if 'passive mode' is set, or no user was logged in when rule was created)\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Passiv hinzugefügt (entweder wenn der „Passive Modus“ aktiviert ist oder kein Benutzer angemeldet war, als die Regel erstellt wurde)\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Agregado pasivamente (cuando el “modo pasivo” está activado o ningún usuario había iniciado sesión cuando se creó la regla)\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ajouté passivement (si le « mode passif » est activé ou si aucun utilisateur n’était connecté lors de la création de la règle)\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aggiunto passivamente (se è attivata la “modalità passiva” o nessun utente era connesso quando la regola è stata creata)\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"수동으로 추가됨 (’수동 모드’가 설정되어 있거나 규칙 생성 시 로그인한 사용자가 없을 경우)\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dodano pasywnie (gdy ustawiono „tryb pasywny” lub żaden użytkownik nie był zalogowany w momencie tworzenia reguły)\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Adicionado passivamente (quando o “modo passivo” está ativado ou nenhum usuário estava logado quando a regra foi criada)\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pasif olarak eklendi (“pasif mod” etkinse veya kural oluşturulurken hiçbir kullanıcı oturum açmamışsa)\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Додано пасивно (якщо увімкнено «пасивний режим» або під час створення правила жоден користувач не був увійшов у систему)\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"غیر فعال طور پر شامل کیا گیا (یا تو اگر \\\"غیر فعال موڈ\\\" سیٹ ہے، یا جب اصول بنایا گیا تو کوئی صارف لاگ ان نہیں تھا)\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"被动添加（当设置了“被动模式”，或在创建规则时没有用户登录时）\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"被动添加（当启用“被动模式”或创建规则时没有用户登录）\"\n          }\n        }\n      }\n    },\n    \"Added Profile\" : {\n      \"comment\" : \"Added Profile\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profil hinzugefügt\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Perfil agregado\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profil ajouté\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profilo aggiunto\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"추가된 프로필\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dodany profil\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Perfil adicionado\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Eklenen Profil\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Доданий профіль\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"حذف کی تصدیق کریں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"已添加的配置文件\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"已添加的配置文件\"\n          }\n        }\n      }\n    },\n    \"All Rules\" : {\n      \"comment\" : \"All Rules\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Alle Regeln\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Todas las Reglas\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Toute les règles\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tutte le Regole\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"모든 규칙\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wszystkie reguły\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Todas as Regras\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tüm Kurallar\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Всі правила\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تمام قواعد\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"全部规则\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"全部規則\"\n          }\n        }\n      }\n    },\n    \"Allow\" : {\n      \"comment\" : \"@Allow\\nAllow\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Erlauben\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Permitir\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Autoriser\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Consenti\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"허용\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zezwól\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Permitir\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"İzin Ver\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Дозволити\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"الاؤ\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"允许\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"允許\"\n          }\n        }\n      }\n    },\n    \"Allow (pid: %@)\" : {\n      \"comment\" : \"Allow (pid: %@)\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Erlauben (pid: %@)\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Permitir (pid: %@)\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Autoriser (pid : %@)\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Consenti (pid: %@)\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"허용 (pid: %@)\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zezwól (pid: %@)\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Permitir (pid: %@)\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"İzin Ver (PID: %@)\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Дозволити (PID: %@)\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"الاؤ (پی آئی ڈی: %@)\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"允许(pid: %@)\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"允許（pid: %@）\"\n          }\n        }\n      }\n    },\n    \"Allow (until: %@)\" : {\n      \"comment\" : \"Allow (until: %@)\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Erlauben (bis: %@)\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Permitir (hasta: %@)\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Autoriser (jusqu’à : %@)\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Consenti (fino a: %@)\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"허용 (기한: %@)\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zezwól (do: %@)\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Permitir (até: %@)\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"İzin Ver (Şuna dek: %@)\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Дозволити (до: %@)\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"الاؤ (تک: %@)\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"允许(直到: %@)\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"允許（直到：%@）\"\n          }\n        }\n      }\n    },\n    \"any address\" : {\n      \"comment\" : \"any address\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"jede Adresse\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"cualquier dirección\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"toute adresse\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ogni indirizzo\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"모든 주소\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"dowolny adres\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"qualquer endereço\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"herhangi bir adres\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"будь-яка адреса\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"کوئی بھی پتہ\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"任意地址\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"任何位址\"\n          }\n        }\n      }\n    },\n    \"any port\" : {\n      \"comment\" : \"any port\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"jeder Port\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"cualquier puerto\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"tout port\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ogni porta\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"모든 포트\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"dowolny port\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"qualquer porta\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"herhangi bir kapı\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"будь-який порт\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"کوئی بھی پورٹ\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"任意端口\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"任何連接埠\"\n          }\n        }\n      }\n    },\n    \"Any program\" : {\n      \"comment\" : \"Any program\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Jedes Programm\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cualquier programa\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tout programme\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ogni programma\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"모든 프로그램\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Jakikolwiek program\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Qualquer programa\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"herhangi bir program\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Будь-яка програма\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"کوئی بھی پروگرام\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"任意程序\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"任何程式\"\n          }\n        }\n      }\n    },\n    \"Apple Programs (automatically allowed & added here if 'allow apple programs' is set)\" : {\n      \"comment\" : \"Apple Programs (automatically allowed & added here if 'allow apple programs' is set)\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Apple-Programme (automatisch zugelassen und hier hinzugefügt, wenn „Apple-Programme erlauben“ aktiviert ist)\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Programas de Apple (permitidos automáticamente y agregados aquí si está configurado 'permitir programas de Apple')\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Programmes Apple (automatiquement approuvé et ajouté ici si 'Autoriser les programmes Apple' est activé)\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Programmi Apple (autorizzati e aggiunti qui automaticamente se è impostato \\\"Consenti programmi Apple\\\")\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Apple 프로그램 ('Apple 프로그램 허용' 설정에 따라 자동으로 허용 및 추가됨)\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Programy Apple (automatycznie dozwolone i dodawane tutaj, jeśli ustawiono opcję „zezwól programom Apple”)\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Programas da Apple (automaticamente adicionados aqui se ‘permitir programas Apple’ está selecionado)\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Apple Programları (“Apple programlarına izin ver” ayarlıysa buraya kendiliğinden eklenir ve izin verilir)\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Програми Apple (автоматично дозволяються й додаються сюди, якщо увімкнено «Дозволяти програми Apple»)\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ایپل پروگرامز (اگر 'ایپل پروگرامز کو الاؤ' سیٹ کیا جائے تو خودکار طور پر یہاں شامل اور الاؤ دیا جاتا ہے)\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Apple 程序（如果设置了“允许 Apple 程序”，则自动允许并添加到此处）\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Apple 程式（若啟用「允許 Apple 程式」，則會自動允許並新增至此）\"\n          }\n        }\n      }\n    },\n    \"Block\" : {\n      \"comment\" : \"Block\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Blockieren\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bloquear\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bloquer\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Blocca\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"차단\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Blokuj\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bloquear\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Engelle\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Блокувати\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"بلاک\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"阻止\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"阻擋\"\n          }\n        }\n      }\n    },\n    \"Block (pid: %@)\" : {\n      \"comment\" : \"Block (pid: %@)\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Blockieren (pid: %@)\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bloquear (pid: %@)\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bloquer (pid : %@)\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Blocca (pid: %@)\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"차단 (pid: %@)\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Blokuj (pid: %@)\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bloquear (pid: %@)\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Engelle (PID: %@)\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Блокувати (PID: %@)\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"بلاک کریں (پی آئی ڈی: %@)\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"阻止 (pid: %@)\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"阻擋（pid: %@）\"\n          }\n        }\n      }\n    },\n    \"Block (until: %@)\" : {\n      \"comment\" : \"Block (until: %@)\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Blockieren (bis: %@)\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bloquear (hasta: %@)\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bloquer (jusqu’à : %@)\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Blocca (fino a: %@)\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"차단 (기한: %@)\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Blokuj (do: %@)\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bloquear (até: %@)\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Engelle (Şuna dek: %@)\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Блокувати (до: %@)\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"بلاک کریں (تک: %@)\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"阻止 (直到: %@)\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"阻擋 (直到：%@)\"\n          }\n        }\n      }\n    },\n    \"Cancel\" : {\n      \"comment\" : \"Cancel\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Abbrechen\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cancelar\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Annuler\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cancella\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"취소\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Anuluj\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cancelar\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vazgeç\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Скасувати\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"منسوخ کریں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"取消\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"取消\"\n          }\n        }\n      }\n    },\n    \"Clean up rules referencing deleted, expired, or terminated items?\" : {\n      \"comment\" : \"Clean up rules referencing deleted, expired, or terminated items?\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Regeln bereinigen, die auf gelöschte, abgelaufene oder beendete Elemente verweisen?\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"¿Reglas de limpieza que hacen referencia a elementos eliminados, vencidos o finalizados?\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nettoyer les règles faisant référence à des éléments supprimés, expirés ou terminés ?\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vuoi pulire le regole che fanno riferimento agli elementi eliminati, scaduti o terminati?\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"삭제, 만료, 또는 중지된 항목을 참조하는 규칙을 정리할까요?\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Czy reguły czyszczenia odnoszą się do elementów usuniętych, wygasłych lub zamkniętych?\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Limpar regras que fazem referência a itens excluídos, expirados ou encerrados?\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Silinen, süresi dolan veya sonlandırılan öğelere atıfta bulunan temizleme kurallarını mı istiyorsunuz?\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Видалити правила, що посилаються на видалені, прострочені або завершені елементи?\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"حذف شدہ، ختم شدہ یا ختم شدہ اشیاء کے حوالے سے قواعد کو صاف کرنا چاہتے ہیں؟\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"清理引用已删除、过期或终止的项目的规则？\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"清理引用已刪除、過期或終止項目的規則？\"\n          }\n        }\n      }\n    },\n    \"Cleaned up %ld rules\" : {\n      \"comment\" : \"Cleaned up %ld rules\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%ld Regeln aufgeräumt\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Se limpiaron %ld reglas\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%ld règles nettoyées\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%ld regole pulite\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%ld개의 규칙을 정리함\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wyczyszczono %ld reguł\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"As regras de %ld foram limpas\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%ld kural temizlendi\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Видалено %ld правил\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%ld قواعد کو صاف کیا گیا\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"已清理 %ld 条规则\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"已清理 %ld 條規則\"\n          }\n        }\n      }\n    },\n    \"Confirm Deletion\" : {\n      \"comment\" : \"Confirm Deletion\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Löschung bestätigen\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Confirmar eliminación\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Confirmer la suppression\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Conferma eliminazione\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"삭제 확인\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Potwierdź usunięcie\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Confirmar exclusão\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Silmeyi Onayla\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Підтвердити видалення\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"حذف کی تصدیق کریں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"确认删除\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"确认删除\"\n          }\n        }\n      }\n    },\n    \"Continue\" : {\n      \"comment\" : \"Continue\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Fortfahren\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Continuar\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Continuer\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Continua\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"계속\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kontynuuj\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Coninuar\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sürdür\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Продовжити\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"جاری رکھیں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"继续\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"繼續\"\n          }\n        }\n      }\n    },\n    \"Current profile is now: '%@'.\" : {\n      \"comment\" : \"Current profile is now: '%@'.\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aktuelles Profil ist nun: „%@“.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"El perfil actual ahora es: “%@”.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Le profil actuel est désormais : « %@ ».\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Il profilo attuale è ora: \\\"%@\\\".\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"현재 프로필은 \\\"%@\\\"입니다.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aktualny profil to: „%@”.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"O perfil atual agora é: “%@”.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Geçerli profil şimdi: “%@”.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Поточний профіль: «%@».\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"موجودہ پروفائل اب ہے: '%@'۔\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"当前配置文件为：“%@”。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"当前配置文件为：”%@”。\"\n          }\n        }\n      }\n    },\n    \"Current Profile: %@\" : {\n      \"comment\" : \"Current Profile: %@\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aktuelles Profil: %@\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Perfil actual: %@\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profil actuel : %@\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profilo attuale: %@\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"현재 프로필: %@\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aktualny profil: %@\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Perfil atual: %@\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Geçerli profil: %@\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Поточний профіль: %@\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"موجودہ پروفائل: %@\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"当前配置文件：%@\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"当前配置文件：%@\"\n          }\n        }\n      }\n    },\n    \"Current Profile: Default\" : {\n      \"comment\" : \"Current Profile: Default\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aktuelles Profil: Default\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Perfil actual: Default\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profil actuel : Default\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profilo attuale: Default\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"현재 프로필: Default\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aktualny profil: Default\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Perfil atual: Default\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Geçerli profil: Saptanmış\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Поточний профіль: Default\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"موجودہ پروفائل: Default\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"当前配置文件：Default\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"当前配置文件：Default\"\n          }\n        }\n      }\n    },\n    \"Default\" : {\n      \"comment\" : \"Default\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Default\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Default\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Default\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Default\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Default\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Default\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Default\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Saptanmış\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Default\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Default\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"默认\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Default\"\n          }\n        }\n      }\n    },\n    \"Delete\" : {\n      \"comment\" : \"Delete\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Löschen\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Eliminar\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Supprimer\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Elimina\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"삭제\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Usuń\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Excluir\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sil\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Видалити\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"حذف کریں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"删除\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"刪除\"\n          }\n        }\n      }\n    },\n    \"Delete %@\" : {\n      \"comment\" : \"Delete %@\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ löschen\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Eliminar %@\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Supprimer %@\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Elimina %@\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ 삭제\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Usuń %@\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Excluir %@\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sil: %@\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Видалити %@\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ حذف کریں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"删除 %@\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"删除%@\"\n          }\n        }\n      }\n    },\n    \"Delete profile: '%@'?\" : {\n      \"comment\" : \"Delete profile: '%@'?\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profil „%@“ löschen?\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"¿Eliminar el perfil “%@”?\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Supprimer le profil : « %@ » ?\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Eliminare il profilo \\\"%@\\\"?\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"프로필 \\\"%@\\\"을(를) 삭제하시겠습니까?\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Usunąć profil „%@”?\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Excluir o perfil “%@”?\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"“%@” profili silinsin mi?\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Видалити профіль «%@»?\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"پروفائل '%@' کو حذف کریں؟\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"删除配置文件：“%@”？\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"删除配置文件：”%@”？\"\n          }\n        }\n      }\n    },\n    \"Delete Rule?\" : {\n      \"comment\" : \"Delete Rule?\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Regel löschen?\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"¿Eliminar regla?\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Supprimer la règle ?\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Eliminare la regola?\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"규칙을 삭제하시겠습니까?\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Usunąć regułę?\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Excluir regra?\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kural silinsin mi?\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Видалити правило?\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"قاعدہ حذف کریں؟\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"删除规则？\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"刪除規則？\"\n          }\n        }\n      }\n    },\n    \"Directory Rules apply to all items within the directory\" : {\n      \"comment\" : \"Directory Rules apply to all items within the directory\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Verzeichnisregeln gelten für alle Objekte innerhalb des Verzeichnisses\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Las Reglas de Directorio se aplican a todos los elementos dentro del directorio\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Les règles de répertoire s'appliquent à tous les éléments du répertoire\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Le regole della directory si applicano a tutti gli elementi all'interno della directory\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"디렉토리 규칙은 디렉토리 내 모든 항목에 적용됩니다\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Reguły katalogu dotyczą wszystkich elementów w katalogu\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Regras do Diretório se aplicam à todos os itens contidos no diretório\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dizin kuralları, dizindeki tüm öğelere uygulanır\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Правила каталогів застосовуються до всіх елементів у каталозі.\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ڈائریکٹری قواعد ڈائریکٹری کے اندر موجود تمام اشیاء پر لاگو ہوتی ہیں۔\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"目录规则适用于目录内的所有项目\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"目錄規則適用於該目錄內的所有項目\"\n          }\n        }\n      }\n    },\n    \"Disable\" : {\n      \"comment\" : \"Disable\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Deaktivieren\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desactivado\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Désactiver\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Disabilita\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"비활성화\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wyłącz\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desabilitar\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Devre Dışı Bırak\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Вимкнути\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"غیر فعال کریں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"禁用\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"停用\"\n          }\n        }\n      }\n    },\n    \"Disable %@\" : {\n      \"comment\" : \"Disable %@\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ deaktivieren\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desactivar %@\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Désactiver %@\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Disabilita %@\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ 비활성화\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wyłącz %@\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desativar %@\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Devre Dışı Bırak: %@\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Вимкнути %@\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ کو غیر فعال کریں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"禁用 %@\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"禁用%@\"\n          }\n        }\n      }\n    },\n    \"Display Path(s)\" : {\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pfad/Pfade anzeigen\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mostrar ruta(s)\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Afficher le(s) chemin(s)\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mostra percorso/i\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"경로 표시\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wyświetl ścieżkę(i)\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Exibir caminho(s)\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Yol(ları) Göster\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Показати шлях(и)\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"راستہ(جات) دکھائیں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"显示路径\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"显示路径\"\n          }\n        }\n      }\n    },\n    \"Edit %@\" : {\n      \"comment\" : \"Edit %@\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ bearbeiten\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Editar %@\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modifier %@\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modifica %@\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ 편집\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Edytuj %@\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Editar %@\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Düzenle: %@\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Редагувати %@\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ میں ترمیم کریں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"编辑 %@\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"编辑%@\"\n          }\n        }\n      }\n    },\n    \"Enable\" : {\n      \"comment\" : \"Enable\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aktivieren\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Activado\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Activer\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Abilita\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"활성화\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Włącz\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Habilitar\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Engelle\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Увімкнути\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"فعال کریں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"启用\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"啟用\"\n          }\n        }\n      }\n    },\n    \"Enable %@\" : {\n      \"comment\" : \"Enable %@\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ aktivieren\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Activar %@\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Activer %@\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Abilita %@\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ 활성화\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Włącz %@\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ativar %@\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Etkinleştir: %@\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Увімкнути %@\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ کو فعال کریں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"启用 %@\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"启用%@\"\n          }\n        }\n      }\n    },\n    \"ERROR: activation failed\" : {\n      \"comment\" : \"ERROR: activation failed\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"FEHLER: Aktivierung fehlgeschlagen\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ERROR: activación fallida\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ERREUR: échec de l’activation\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ERRORE: Attivazione fallita\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"오류: 활성화 실패\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"BŁĄD: aktywacja nie powiodła się\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ERRO: ativação falhou\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"HATA: Etkinleştirme başarısız\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ПОМИЛКА: активація не вдалася\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"خطا: فعال کرنے میں ناکامی\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"错误：激活失败\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"錯誤：啟動失敗\"\n          }\n        }\n      }\n    },\n    \"ERROR: Enter a non-zero duration\" : {\n      \"comment\" : \"ERROR: Enter a non-zero duration\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"FEHLER: Geben Sie eine Dauer ungleich Null ein\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ERROR: Introduzca una duración distinta de cero\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ERREUR : Entrez une durée non nulle\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ERRORE: Inserire una durata diversa da zero\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"오류: 0이 아닌 지속 시간을 입력하세요\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"BŁĄD: Wprowadź niezerowy czas trwania\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ERRO: Insira uma duração diferente de zero\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"HATA: Sıfırdan farklı bir süre girin\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ПОМИЛКА: Введіть ненульову тривалість\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"خرابی: صفر سے مختلف دورانیہ درج کریں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"错误：请输入非零的持续时间\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"錯誤：請輸入非零的持續時間\"\n          }\n        }\n      }\n    },\n    \"ERROR: Failed to cleanup rules\" : {\n      \"comment\" : \"ERROR: Failed to cleanup rules\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"FEHLER: Aufräumen der Regeln fehlgeschlagen\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ERROR: Fallo al limpiar las reglas\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Erreur : échec du nettoyage des règles\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ERRORE: Pulizia regole non completata\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"오류: 규칙 정리 실패\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"BŁĄD: Nie udało się wyczyścić reguł\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ERRO: Falha ao limpar regras\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"HATA: Kurallar temizlenemedi\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ПОМИЛКА: не вдалося видалити правила\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"خرابی: اصولوں کی صفائی میں ناکامی\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"错误：无法清理规则\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"錯誤：清理規則失敗\"\n          }\n        }\n      }\n    },\n    \"ERROR: Failed to export rules\" : {\n      \"comment\" : \"ERROR: Failed to export rules\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"FEHLER: Exportieren der Regeln fehlgeschlagen\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ERROR: Fallo al exportar las reglas\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Erreur : échec de l'exportation des règles\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ERRORE: Esportazione delle regole non completata\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"오류: 규칙 내보내기 실패\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"BŁĄD: Nie udało się wyeksportować reguł\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ERRO: Falha na exportação de regras\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"HATA: Kurallar dışa aktarılamadı\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ПОМИЛКА: не вдалося експортувати правила\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"خرابی: اصولوں کو برآمد کرنے میں ناکامی\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"错误：无法导出规则\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"錯誤：規則匯出失敗\"\n          }\n        }\n      }\n    },\n    \"ERROR: Failed to hash %@\" : {\n      \"comment\" : \"ERROR: Failed to hash %@\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"FEHLER: Hashing von %@ fehlgeschlagen\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ERROR: No se pudo generar el hash de %@\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ERREUR : Échec du hachage de %@\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ERRORE: Impossibile generare l’hash di %@\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"오류: %@ 해시 생성 실패\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"BŁĄD: Nie udało się wygenerować skrótu %@\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ERRO: Falha ao gerar o hash de %@\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"HATA: %@ karması oluşturulamadı\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ПОМИЛКА: Не вдалося обчислити хеш %@\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"خرابی: %@ کا ہیش بنانے میں ناکام\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"错误：哈希%@失败\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"錯誤：雜湊%@失敗\"\n          }\n        }\n      }\n    },\n    \"ERROR: Failed to import rules\" : {\n      \"comment\" : \"ERROR: Failed to import rules\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"FEHLER: Importieren der Regeln fehlgeschlagen\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ERROR: Fallo al importar las reglas\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Erreur : échec de l'importation des règles\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ERRORE: Importazione delle regole non completata\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"오류: 규칙 가져오기 실패\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"BŁĄD: Nie udało się zaimportować reguł\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ERRO: Falha na importação de regras\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"HATA: Kurallar içe aktarılamadı\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ПОМИЛКА: не вдалося імпортувати правила\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"خرابی: اصولوں کو درآمد کرنے میں ناکامی\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"错误：无法导入规则\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"錯誤：規則匯入失敗\"\n          }\n        }\n      }\n    },\n    \"ERROR: failed to load patrons\" : {\n      \"comment\" : \"ERROR: failed to load patrons\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"FEHLER: Unterstützer konnten nicht geladen werden\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ERROR: fallo al cargar patrones\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Erreur : échec du chargement des patrons\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ERRORE: Caricamento patrons non completato\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"오류: Patron 후원자 불러오기 실패\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"BŁĄD: nie udało się załadować patronów\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ERRO: Falha ao carregar patrocinadores\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"HATA: Aboneler yüklenemedi\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ПОМИЛКА: не вдалося завантажити список патронів\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"خرابی: سرپرستوں کو لوڈ کرنے میں ناکامی\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"错误：无法加载赞助者\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"錯誤：載入贊助者失敗\"\n          }\n        }\n      }\n    },\n    \"ERROR: invalid path\" : {\n      \"comment\" : \"ERROR: invalid path\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"FEHLER: Ungültiger Pfad\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ERROR: ruta no válida\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Erreur : chemin invalide\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ERRORE: Percorso non valido\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"오류: 유효하지 않은 경로\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"BŁĄD: nieprawidłowa ścieżka\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ERRO: Caminho inválido\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"HATA: Geçersiz yol\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ПОМИЛКА: некоректний шлях\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"خرابی: نا درست راستہ\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"错误：路径无效\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"錯誤：無效的路徑\"\n          }\n        }\n      }\n    },\n    \"ERROR: invalid port\" : {\n      \"comment\" : \"ERROR: invalid port\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"FEHLER: Ungültiger Port\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ERROR: puerto no válido\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Erreur : port invalide\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ERRORE: Porta non valida\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"오류: 유효하지 않은 포트\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"BŁĄD: nieprawidłowy port\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ERRO: Porta inválida\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"HATA: Geçersiz kapı\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ПОМИЛКА: некоректний порт\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"خرابی: نا درست پورٹ\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"错误：端口无效\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"錯誤：無效的連接埠\"\n          }\n        }\n      }\n    },\n    \"ERROR: invalid regex\" : {\n      \"comment\" : \"ERROR: invalid regex\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"FEHLER: Ungültiger regulärer Ausdruck\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ERROR: regex no válido\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Erreur : regex invalide\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ERRORE: Espressione regolare non corretta\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"오류: 유효하지 않은 정규 표현식\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"BŁĄD: nieprawidłowe wyrażenie regularne\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ERRO: Expressão regular inválida\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"HATA: Geçersiz düzenli ifade\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ПОМИЛКА: некоректний регулярний вираз\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"خرابی: نا درست ریگولر ایکسپریشن\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"错误：正则表达式无效\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"錯誤：無效的正則表達式\"\n          }\n        }\n      }\n    },\n    \"error: update check failed\" : {\n      \"comment\" : \"error: update check failed\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Fehler: Prüfen auf Updates fehlgeschlagen\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"error: falló la verificación de actualización\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Erreur : la recherche de mise à jour a échoué\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"errore: impossibile controllare la disponibilità di aggiornamenti\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"오류: 업데이트 확인 실패\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"błąd: nie udało się sprawdzić aktualizacji\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ERRO: Falha na verificação de update\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"HATA: Güncelleme denetimi başarısız\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ПОМИЛКА: не вдалося перевірити оновлення\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"خرابی: اپ ڈیٹ چیک میں ناکامی\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"错误：更新检查失败\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"錯誤：更新檢查失敗\"\n          }\n        }\n      }\n    },\n    \"Extensions must be manually approved via System Settings (General > Login Items & Extensions > Network Extensions).\" : {\n      \"comment\" : \"Extensions must be manually approved via System Settings (General > Login Items & Extensions > Network Extensions).\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Erweiterungen müssen manuell über die Systemeinstellungen (Allgemein > Anmeldeobjekte und Erweiterungen > Netzwerkerweiterungen) genehmigt werden.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Las extensiones deben aprobarse manualmente a través de Configuración del sistema (General > Elementos de inicio de sesión y extensiones > Extensiones de red).\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Les extensions doivent être approuvées manuellement via les paramètres système (Général > Éléments de connexion et extensions > Extensions réseau).\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Le estensioni devono essere approvate manualmente tramite Impostazioni di sistema (Generale > Elementi di accesso ed estensioni > Estensioni di rete).\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"확장 프로그램은 시스템 설정(일반 > 로그인 항목 및 확장 프로그램 > 네트워크 확장 프로그램)을 통해 수동으로 승인되어야 합니다.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rozszerzenia muszą zostać zatwierdzone ręcznie w Ustawieniach systemowych (Ogólne > Rzeczy i rozszerzenia otwierane podczas logowania > Rozszerzenia sieciowe).\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"As extensões devem ser aprovadas manualmente por meio das Configurações do sistema (Geral > Itens de login e extensões > Extensões de rede).\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Uzantılar, Sistem Ayarları (Genel > Oturum Açma Öğeleri ve Uzantılar > Ağ Uzantıları) üzerinden manuel olarak onaylanmalıdır.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Розширення потрібно схвалити вручну в «Налаштуваннях безпеки» (Загальні > Автозапуск і розширення > Мережеві розширення).\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ایکسٹینشنز کو مینوئل طور پر سسٹم سیٹنگز (جنرل > لاگ ان آئٹمز اینڈ ایکسٹینشنز > نیٹ ورک ایکسٹینشنز) کے ذریعے منظور کرنا ہوگا۔\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"必须通过系统设置（通用 > 登录项和扩展 > 网络扩展）手动批准扩展。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"必須在「系統設定」（一般 > 登入項目與延伸功能 > 網路延伸功能）中手動核准延伸功能。\"\n          }\n        }\n      }\n    },\n    \"failed to activate network extension\" : {\n      \"comment\" : \"failed to activate network extension\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Netzwerkerweiterung konnte nicht aktiviert werden\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"falló al activar la extensión de red\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"échec de l’activation de l’extension du réseau\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Impossibile attivare l’estensione di rete\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"네트워크 확장 프로그램 활성화 실패\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"nie udało się aktywować rozszerzenia sieciowego\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"falha ao tentar ativar extensão de rede\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ağ genişletmesi etkinleştirilemedi\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"не вдалося активувати мережеве розширення\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"نیٹ ورک ایکسٹینشن کو فعال کرنے میں ناکامی\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"无法激活网络扩展\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"啟動網路延伸功能失敗\"\n          }\n        }\n      }\n    },\n    \"failed to activate network filter\" : {\n      \"comment\" : \"failed to activate network filter\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Netzwerkfilter konnte nicht aktiviert werden\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"falló al activar el filtro de red\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"échec de l’activation du filtre réseau\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Impossibile attivare il filtro di rete\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"네트워크 필터 활성화 실패\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"nie udało się aktywować filtra sieciowego\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"falha ao tentar ativar filtro de rede\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ağ süzgeci etkinleştirilemedi\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"не вдалося активувати мережевий фільтр\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"نیٹ ورک فلٹر کو فعال کرنے میں ناکامی\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"无法激活网络过滤器\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"啟用網路過濾器失敗\"\n          }\n        }\n      }\n    },\n    \"failed to activate system extension\" : {\n      \"comment\" : \"failed to activate system extension\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Systemerweiterung konnte nicht aktiviert werden\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"falló al activar la extensión del sistema\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"échec de l’activation de l’extension système\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Impossibile attivare l’estensione di sistema\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"시스템 확장 프로그램 활성화 실패\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"nie udało się aktywować rozszerzenia systemu\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"falha ao tentar ativar extensão do sistema\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"sistem genişletmesi etkinleştirilemedi\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"не вдалося активувати системне розширення\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"سسٹم ایکسٹینشن کو فعال کرنے میں ناکامی\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"无法激活系统扩展\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"啟動系統延伸功能失敗\"\n          }\n        }\n      }\n    },\n    \"failed to activate system/network extension\" : {\n      \"comment\" : \"failed to activate system/network extension\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"System-/Netzwerkerweiterung konnte nicht aktiviert werden\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"falló al activar la extensión del sistema/red\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"échec de l’activation de l’extension système/réseau\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Impossibile attivare l’estensione di sistema/rete\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"시스템/네트워크 확장 프로그램 활성화 실패\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"nie udało się aktywować rozszerzenia systemowego/sieciowego\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"falha ao tentar ativar extensão de sistema/rede\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"sistem/ağ genişletmesi etkinleştirilemedi\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"не вдалося активувати системне або мережеве розширення\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"سسٹم/نیٹ ورک ایکسٹینشن کو فعال کرنے میں ناکامی\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"无法激活系统/网络扩展\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"啟動系統/網路延伸功能失敗\"\n          }\n        }\n      }\n    },\n    \"Full URL: %@\" : {\n      \"comment\" : \"Full URL: %@\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vollständige URL: %@\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"URL completo: %@\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"URL complète: %@\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"URL Completo: %@\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"전체 URL: %@\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pełny adres URL: %@\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"URL completo: %@\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tam URL: %@\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Повний URL: %@\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"مکمل یو آر ایل: %@\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"完整网址：%@\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"完整網址：%@\"\n          }\n        }\n      }\n    },\n    \"Global Rules apply to all paths\" : {\n      \"comment\" : \"Global Rules apply to all paths\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Globale Regeln gelten für alle Pfade\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Las Reglas Globales se aplican a todas las rutas\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Les Règles Globales s’appliquent à tous les chemins\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Le Regole Globali sono valide per tutti i percorsi\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"전역 규칙은 모든 경로에 적용됩니다\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Reguły globalne dotyczą wszystkich ścieżek\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Regras Globais se aplicam a todos os caminhos\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Global kurallar tüm yollara uygulanır\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Глобальні правила застосовуються до всіх шляхів\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"گلوبل رولز تمام راستوں پر لاگو ہوتے ہیں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"全局规则适用于所有路径\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"全域規則適用於所有路徑\"\n          }\n        }\n      }\n    },\n    \"Imported %ld rules\" : {\n      \"comment\" : \"Imported %ld rules\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%ld Regeln importiert\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Reglas %ld importadas\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%ld règles importées\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%ld regole importate\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%ld개의 규칙을 가져옴\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zaimportowano %ld reguł\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%ld regras importadas\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%ld kural içe aktarıldı\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Імпортовано %ld правил\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%ld رولز درآمد کیے گئے\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"已导入 %ld 条规则\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"已匯入 %ld 條規則\"\n          }\n        }\n      }\n    },\n    \"Installed version (%@),\\r\\nis the latest.\" : {\n      \"comment\" : \"Installed version (%@),\\r\\nis the latest.\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Die installierte Version (%@)\\r\\nist die neuste.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"La versión instalada (%@), es la más reciente.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"La version installée (%@) est la plus récente.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"La versione installata (%@) è l’ultima disponibile\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"설치된 버전(%@)이 최신입니다.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zainstalowana wersja (%@),\\njest najnowsza.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Versão instalada (%@), é a mais recente\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"kurulu sürüm (%@), günceldir\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Встановлена версія (%@) є найновішою.\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"انسٹال ورژن (%@)،\\r\\nسب سے تازہ ترین ہے۔\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"已安装版本 (%@)，\\n是最新版本。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"已安裝版本（%@）為最新版本。\"\n          }\n        }\n      }\n    },\n    \"Invalid Profile Name\" : {\n      \"comment\" : \"Invalid Profile Name\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ungültiger Profilname\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nombre de perfil no válido\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nom de profil invalide\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nome profilo non valido\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"잘못된 프로필 이름\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nieprawidłowa nazwa profilu\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nome de perfil inválido\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Geçersiz Profil Adı\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Неправильна назва профілю\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"غلط پروفائل نام\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"配置文件名称无效\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"配置文件名称无效\"\n          }\n        }\n      }\n    },\n    \"is connecting to %@\" : {\n      \"comment\" : \"is connecting to %@\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"verbindet sich mit %@\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"se está conectando a %@\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"se connecte à %@\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"si sta connettendo a %@\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"프로세스가 다음으로 연결 시도 중: %@\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"łączy się z %@\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"está conectando a %@\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ konumuna bağlanıyor\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"підключається до %@\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"منسلک ہو رہا ہے %@\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"正在连接到 %@\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"正在連線至 %@\"\n          }\n        }\n      }\n    },\n    \"Key\" : {\n      \"extractionState\" : \"manual\",\n      \"localizations\" : {\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ключ\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"کلید\"\n          }\n        }\n      },\n      \"shouldTranslate\" : false\n    },\n    \"LuLu must run from within /Applications\\r\\n\" : {\n      \"comment\" : \"LuLu must run from within /Applications\\r\\n\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu muss aus /Applications heraus ausgeführt werden\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu debe ejecutarse desde /Applications\\n\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu doit être exécuté depuis /Applications\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu deve essere eseguito da /Applications\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu는 /Applications 내에서 실행해야 합니다\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu musi być uruchamiany z katalogu /Applications\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"O LuLu deve ser executado a partir de /Applications\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu, /Applications klasöründen çalıştırılmalıdır\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu має запускатися з /Applications\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu کو /Applications کے اندر سے چلایا جانا چاہیے\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu 必须从 /Applications 中运行\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu 必須從 /Applications 中運行\"\n          }\n        }\n      }\n    },\n    \"LuLu: disabled\" : {\n      \"comment\" : \"LuLu: disabled\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu: deaktiviert\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu: desactivado\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu : désactivé\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu: Disabilitato\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu: 비활성화됨\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu: wyłączona\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu: desabilitado\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu: Devre dışı\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu: вимкнено\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu: غیر فعال\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu: 禁用\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu：停用\"\n          }\n        }\n      }\n    },\n    \"LuLu: enabled\" : {\n      \"comment\" : \"LuLu: enabled\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu: aktiviert\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu: activado\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu : activé\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu: Abilitato\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu: 활성화됨\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu: włączona\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu: habilitado\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu: Etkin\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu: увімкнено\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu: فعال\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu: 启用\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu：啟用\"\n          }\n        }\n      }\n    },\n    \"LuLu's Network Extension Is Not Running\" : {\n      \"comment\" : \"LuLu's Network Extension Is Not Running\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLus Netzwerkerweiterung läuft nicht\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"La Extensión de Red de LuLu no está en ejecución\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"L’extension réseau de LuLu ne fonctionne pas\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"L’estensione di rete di LuLu non è attiva\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu의 네트워크 확장 프로그램이 실행되고 있지 않습니다\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rozszerzenie sieciowe LuLu nie działa\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"A Extensão de Rede do LuLu não está rodando\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu’nun ağ genişletmesi çalışmıyor\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Мережеве розширення LuLu не працює\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu کا نیٹ ورک ایکسٹینشن چل رہا نہیں ہے\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu 的网络扩展未运行\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu 的網路延伸功能未執行\"\n          }\n        }\n      }\n    },\n    \"More Info\" : {\n      \"comment\" : \"More Info\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Weitere Informationen\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Más Información\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Plus d’infos\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Più informazioni\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"추가 정보\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Więcej informacji\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mais Informações\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Daha Fazla Bilgi\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Більше інформації\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"مزید معلومات\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"更多信息\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"更多資訊\"\n          }\n        }\n      }\n    },\n    \"New profile '%@' saved and activated.\" : {\n      \"comment\" : \"New profile '%@' saved and activated.\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Neues Profil „%@“ gespeichert und aktiviert.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nuevo perfil “%@” guardado y activado.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nouveau profil « %@ » enregistré et activé.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nuovo profilo \\\"%@\\\" salvato e attivato.\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"새 프로필 \\\"%@\\\"이(가) 저장되고 활성화되었습니다.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nowy profil „%@” został zapisany i aktywowany.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Novo perfil “%@” salvo e ativado.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Yeni “%@” profili kaydedildi ve etkinleştirildi.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Новий профіль «%@» збережено та активовано.\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"یا پروفائل '%@' محفوظ کر لیا گیا ہے اور فعال کر دیا گیا ہے۔\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"新配置文件“%@”已保存并激活。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"新配置文件”%@”已保存并激活。\"\n          }\n        }\n      }\n    },\n    \"Next\" : {\n      \"comment\" : \"Next\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Weiter\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Siguiente\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Suivant\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Avanti\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"다음\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dalej\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Avançar\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sonraki\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Далі\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ٹھیک ہے\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"下一步\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"下一步\"\n          }\n        }\n      }\n    },\n    \"none\" : {\n      \"comment\" : \"none\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"keine\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ninguno\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"aucun\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"nessuno\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"없음\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"nic\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"nenhum(a)\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"yok\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"жоден\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"کوئی نہیں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"无\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"無\"\n          }\n        }\n      }\n    },\n    \"not applicable\" : {\n      \"comment\" : \"not applicable\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"nicht anwendbar\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"no aplica\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"non applicable\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"non applicabile\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"해당 없음\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"nie dotyczy\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"não se aplica\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"uygulanabilir değil\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"не застосовується\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"لاگو نہیں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"不适用\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"不適用\"\n          }\n        }\n      }\n    },\n    \"Note however:\\r\\n▪ Existing connections will not be impacted.\\r\\n▪ OS traffic (not routed thru LuLu) will not be blocked.\" : {\n      \"comment\" : \"Note however:\\r\\n▪ Existing connections will not be impacted.\\r\\n▪ OS traffic (not routed thru LuLu) will not be blocked.\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Beachte:\\n▪ Bestehende Verbindungen sind nicht betroffen.\\n▪ Betriebssystemverkehr (der nicht über LuLu geleitet wird) wird nicht blockiert.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sin embargo, ten en cuenta:\\n▪ Las conexiones existentes no se verán afectadas.\\n▪ El tráfico del sistema operativo (que no es ruteado a través de LuLu) no será bloqueado.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"A noter cependant :\\n▪ Les connexions existantes ne seront pas affectées.\\n▪ Le trafic OS (non acheminé par LuLu) ne sera pas bloqué.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tieni a mente:\\n * Le connessioni esistente non verranno impattate.\\n * Il traffico di rete del Sistema Operativo (che non passa tramite LuLu) non verrà bloccato.\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"참고 사항:\\r\\n▪ 기존 연결은 영향을 받지 않습니다.\\r\\n▪ (LuLu를 통하지 않는) OS 트래픽은 차단되지 않습니다.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Należy pamiętać że:\\n▪ Istniejące połączenia nie zostaną naruszone.\\n▪ Ruch systemu operacyjnego (niekierowany przez LuLu) nie zostanie zablokowany.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Observação:\\r\\n▪ Conexões existentes não serão impactadas.\\r\\n▪ Tráfego do sistema operacional (não encaminhado pelo LuLu) não será bloqueado.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ancak şuna dikkat edin:\\n ▪ Var olan bağlantılar bundan etkilenmez.\\n▪ İşletim sistemi trafiği (LuLu tarafından yönetilmeyen) engellenmez.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Зверніть увагу:\\n▪ Існуючі з'єднання не будуть порушені.  \\n▪ Системний трафік, який не проходить через LuLu, не буде заблоковано.\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"یہ نوٹ کریں:\\r\\n▪ موجودہ کنیکشن پر کوئی اثر نہیں پڑے گا۔\\r\\n▪ او ایس ٹریفک (جو لولو کے ذریعے روٹ نہیں کیا جاتا ہے) کو بلاک نہیں کیا جائے گا۔\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"请注意：\\n▪ 现有连接不会受到影响。\\n▪ 操作系统流量（未通过 LuLu 路由）不会被阻止。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"請注意：\\n▪ 現有連線不會受影響。\\n▪ 作業系統流量（未經過 LuLu）不會被封鎖。\"\n          }\n        }\n      }\n    },\n    \"Ok\" : {\n      \"comment\" : \"Ok\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"OK\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aceptar\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"OK\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ok\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"확인\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"OK\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"OK\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tamam\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Гаразд\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ٹھیک ہے\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"确定\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"确定\"\n          }\n        }\n      }\n    },\n    \"OK\" : {\n      \"comment\" : \"OK\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ok\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"OK\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"OK\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"OK\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"OK\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"OK\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"OK\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tamam\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ОК\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ٹھیک ہے\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"OK\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"OK\"\n          }\n        }\n      }\n    },\n    \"Old Version of LuLu Installed\" : {\n      \"comment\" : \"Old Version of LuLu Installed\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Veraltete Version von LuLu installiert\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Versión antigua de LuLu instalada\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ancienne version de LuLu installée\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"È installata una vecchia versione di LuLu\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"이전 버전의 LuLu가 설치됨\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zainstalowano starą wersję LuLu\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Versão Antiga do LuLu Instalada.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu’nun eski sürümü kurulu\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Виявлено застарілу версію LuLu\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"لولو کا پرانا ورژن انسٹال ہے\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"已安装旧版本的 LuLu\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"已安裝舊版 LuLu\"\n          }\n        }\n      }\n    },\n    \"Only export user created rules\" : {\n      \"comment\" : \"Only export user created rules\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nur benutzererstellte Regeln exportieren\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Exportar solo las reglas creadas por el usuario\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Exporter uniquement les règles créées par l'utilisateur\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Esporta solo le regole create dall'utente\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"사용자가 생성한 규칙만 내보내기\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Eksportuj tylko reguły utworzone przez użytkownika\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Exportar apenas regras criadas pelo usuário\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Yalnızca kullanıcı tarafından oluşturulan kuralları dışa aktar\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Експортувати лише правила, створені користувачем\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"صرف صارف کی بنائی ہوئی قواعد برآمد کریں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"仅导出用户创建的规则\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"僅導出用戶創建的規則\"\n          }\n        }\n      }\n    },\n    \"Operating System Programs (required for system functionality)\" : {\n      \"comment\" : \"Operating System Programs (required for system functionality)\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Betriebssystemprogramme (für Systemfunktionaliät benötigt)\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Programas del Sistema Operativo (necesarios para la funcionalidad del sistema)\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Programmes du système d'exploitation (nécessaires au fonctionnement du système)\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Programmi del Sistema Operativo (Richiesti per le funzionalità di sistema)\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"운영 체제 프로그램 (시스템 기능에 필요)\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Programy systemu operacyjnego (wymagane do prawidłowego działania systemu)\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Programas do Sistema Operacional (necessários para funcionalidade do sistema)\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"İşletim sistemi programları (sistem işlevselliği için gerekli)\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Системні програми (необхідні для роботи операційної системи)\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"آپریٹنگ سسٹم پروگرامز (سسٹم فنکشنیلٹی کے لیے ضروری)\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"操作系统程序（系统功能所需）\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"作業系統程式（系統功能所需）\"\n          }\n        }\n      }\n    },\n    \"Outgoing traffic will now be blocked.\" : {\n      \"comment\" : \"Outgoing traffic will now be blocked.\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ausgehender Datenverkehr wird jetzt blockiert.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tráfico saliente será bloqueado ahora. \"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Le trafic sortant est désormais bloqué.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Il traffico in uscita non verrà bloccato\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"이제 나가는 트래픽이 차단됩니다.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ruch wychodzący będzie teraz blokowany.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tráfego de saída será bloqueado.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dışarı giden trafik artık engellenecek.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Вихідний трафік тепер буде заблоковано.\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"آؤٹ گوئنگ ٹریفک اب بلاک کر دی جائے گی۔\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"传出的流量将被阻止。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"對外流量將被封鎖。\"\n          }\n        }\n      }\n    },\n    \"Path(s) for %@:\" : {\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pfad/Pfade für %@:\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ruta(s) de %@:\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Chemin(s) pour %@ :\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Percorso/i per %@:\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@의 경로:\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ścieżka(i) dla %@:\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Caminho(s) de %@:\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ için yol(lar):\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Шлях(и) для %@:\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ کے لیے راستہ(جات):\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ 的路径：\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ 的路径：\"\n          }\n        }\n      }\n    },\n    \"Path(s):\" : {\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pfad/Pfade:\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ruta(s):\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Chemin(s) :\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Percorso/i:\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"경로:\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ścieżka(i):\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Caminho(s):\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Yol(lar):\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Шлях(и):\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"راستہ(جات):\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"路径：\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"路径：\"\n          }\n        }\n      }\n    },\n    \"Pre-installed 3rd-party Programs (automatically allowed & added here if 'allow installed applications' is set)\" : {\n      \"comment\" : \"Pre-installed 3rd-party Programs (automatically allowed & added here if 'allow installed applications' is set)\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vorinstallierte Drittanbieterprogramme (automatisch zugelassen und hier hinzugefügt, wenn „Bereits installierte Anwendungen erlauben“ aktiviert ist)\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Programas de terceros preinstalados (permitidos automáticamente y agregados aquí si está configurado 'permitir aplicaciones instaladas')\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Programmes tiers préinstallés (automatiquement autorisés et ajoutés ici si l'option « autoriser les applications installées » est activée)\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Programmi di terze parti pre-installati (approvati automaticamente e mostrati qui se “Abilita applicazioni installate” è attivo)\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"사전에 설치한 타사 프로그램 ('설치된 프로그램 허용' 설정에 따라 자동으로 허용 및 추가됨)\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wstępnie zainstalowane programy innych firm (automatycznie dozwolone i dodawane tutaj, jeśli ustawiono opcję „zezwalaj na zainstalowane aplikacje”)\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Programas Terceirizados Pré-Instalados (automaticamente permitidos e adicionados aqui se ‘permitir aplicações instaladas’ estiver selecionado)\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Önceden kurulu 3. parti uygulamalar (“Kurulu uygulamalara izin ver” ayarlıysa kendiliğinden eklenir ve izin verilir)\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Попередньо встановлені сторонні програми (автоматично дозволяються й додаються сюди, якщо увімкнено «Дозволити встановлені програми»)\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"پہلے سے انسٹال شدہ تھرڈ پارٹی پروگرامز (اگر 'انسٹال شدہ ایپلیکیشنز کو اجازت دیں' سیٹ ہو تو خودکار طور پر اجازت دی جاتی ہے اور یہاں شامل کی جاتی ہے)\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"已安装的第三方程序（如果设置了“允许已安装的应用程序”，则自动允许并添加到此处）\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"已安裝的第三方程式（若啟用「允許已安裝的應用程式」，則會自動允許並新增至此）\"\n          }\n        }\n      }\n    },\n    \"Process Arguments: %@\" : {\n      \"comment\" : \"Process Arguments: %@\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Prozessargumente: %@\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Argumentos Procesados: %@\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Arguments de processus : %@\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Argomenti del processo: %@\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"프로세스 인수: %@\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Argumenty procesu: %@\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Argumentos do Processo: %@\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"İşlem argümanları: %@\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Параметри процесу: %@\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"پروسیس آرگومنٹس: %@\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"进程参数：%@\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Process 參數：%@\"\n          }\n        }\n      }\n    },\n    \"Process Path: %@\" : {\n      \"comment\" : \"Process Path: %@\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Prozesspfad: %@\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ruta del Proceso: %@\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Chemin du processus : %@\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Percorso del processo: %@\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"프로세스 경로: %@\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ścieżka procesu: %@\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Caminho do Processo: %@\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"İşlem yolu: %@\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Шлях процесу: %@\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"پروسیس پاتھ: %@\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"进程路径：%@\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Process 路徑：%@\"\n          }\n        }\n      }\n    },\n    \"Profile name can't be blank\" : {\n      \"comment\" : \"Profile name can't be blank\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profilname darf nicht leer sein\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"El nombre del perfil no puede estar vacío\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Le nom du profil ne peut pas être vide\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Il nome del profilo non può essere vuoto\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"프로필 이름은 비워둘 수 없습니다\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nazwa profilu nie może być pusta\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"O nome do perfil não pode estar vazio\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profil adı boş bırakılamaz\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Назва профілю не може бути порожньою\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"پروفائل کا نام خالی نہیں ہو سکتا\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"配置文件名称不能为空\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"配置文件名稱不能為空\"\n          }\n        }\n      }\n    },\n    \"Profile Switched\" : {\n      \"comment\" : \"Profile Switched\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profil gewechselt\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Perfil cambiado\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profil changé\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profilo cambiato\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"프로필 전환됨\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profil przełączony\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Perfil alterado\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profil Değiştirildi\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Профіль перемкнено\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"پروفائل تبدیل کر دیا گیا ہے\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"配置文件已切换\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"配置文件已切换\"\n          }\n        }\n      }\n    },\n    \"Profile: %@\" : {\n      \"comment\" : \"Profile: %@\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profil: %@\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Perfil: %@\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profil : %@\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profilo: %@\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"프로필: %@\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profil: %@\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Perfil: %@\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profil: %@\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Профіль: %@\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"پروفائل: %@\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"配置文件：%@\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"配置文件：%@\"\n          }\n        }\n      }\n    },\n    \"Profile: Default\" : {\n      \"comment\" : \"Profile: Default\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profil: Default\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Perfil: Default\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profil : Default\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profilo: Default\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"프로필: Default\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profil: Default\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Perfil: Default\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Profil: Saptanmış\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Профіль: Default\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"روفائل: Default\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"配置文件：Default\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"配置文件：Default\"\n          }\n        }\n      }\n    },\n    \"Programs within \\\"%@/\\\"\" : {\n      \"comment\" : \"Programs within \\\"%@/\\\"\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Programme in \\\"%@/\\\"\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Programas dentro de \\\"%@/\\\"\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Programmes dans \\\"%@/\\\"\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Programmi all'interno di \\\"%@/\\\"\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"\\\"%@/\\\" 내 프로그램\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Programy w \\\"%@/\\\"\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Programas em “%@/“\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"“%@/“ içindeki uygulamalar\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Програми в \\\"%@/\\\"\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"پروگرامز اندر \\\"%@/\\\"\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"“%@/”内的程序\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"\\\"%@/\\\" 中的程式\"\n          }\n        }\n      }\n    },\n    \"Quit\" : {\n      \"comment\" : \"Quit\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Beenden\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cerrar\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Quitter\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Termina\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"종료\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wyjdź\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sair\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Çık\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Завершити\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ختم کریں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"关闭\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"關閉\"\n          }\n        }\n      }\n    },\n    \"Quit LuLu?\" : {\n      \"comment\" : \"Quit LuLu?\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu beenden?\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cerrar LuLu?\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Quitter LuLu ?\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Terminare LuLu?\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu를 종료할까요?\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wyjść z LuLu?\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sair do LuLu\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu’dan çıkılsın mı?\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Завершити роботу з LuLu?\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"لولو کو ختم کریں؟\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"关闭LuLu ？\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"關閉 LuLu？\"\n          }\n        }\n      }\n    },\n    \"Reverse Domain: %@\" : {\n      \"comment\" : \"Reverse Domain %@\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Reverse Domain: %@\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dominio Inverso: %@\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Domaine inversé : %@\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dominio inverso: %@\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"리버스 도메인: %@\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Reverse Domain: %@\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Domínio Reverso: %@\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ters etki alanı: %@\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Зворотний домен: %@\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ریورس ڈومین: %@\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"反向域 %@\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"反向網域：%@\"\n          }\n        }\n      }\n    },\n    \"Rule\" : {\n      \"comment\" : \"Rule\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Regel\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Regla\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Règle\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Regola\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"규칙\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Reguła\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Regra\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kural\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Правило\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"اصول\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"规则\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"规则\"\n          }\n        }\n      }\n    },\n    \"Rules\" : {\n      \"comment\" : \"Rules\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Regeln\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Reglas\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Règles\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Regole\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"규칙들\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Reguły\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Regras\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kurallar\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Правила\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"اصول\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"规则\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"规则\"\n          }\n        }\n      }\n    },\n    \"rules.json\" : {\n      \"comment\" : \"rules.json\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"rules.json\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"reglas.json\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"rules.json\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"rules.json\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"rules.json\"\n          }\n        }\n      },\n      \"shouldTranslate\" : false\n    },\n    \"See log for (more) details\" : {\n      \"comment\" : \"See log for (more) details\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Prüfe das Log für (weitere) Details\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Consulta el registro para más detalles\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Voir le journal pour (plus) de détails\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vedi i log per altre informazioni\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"더 자세한 사항은 로그를 참조하세요\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zobacz dziennik, aby uzyskać (więcej) szczegółów\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Veja registro para (mais) detalhes\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ayrıntılar için günlüğe bakın\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Дивіться лог для детальнішої інформації\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"مزید تفصیلات کے لیے لاگ دیکھیں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"查看日志了解更多详细信息\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"請查看日誌以獲取（更多）詳細資訊\"\n          }\n        }\n      }\n    },\n    \"This must be uninstalled before continuing. Click 'More Info' to learn how to uninstall it\" : {\n      \"comment\" : \"This must be uninstalled before continuing\\r\\n.Click 'More Info' to learn how to uninstall it.\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dies muss zuerst deinstalliert werden.\\r\\nKlicke auf „Weitere Informationen“, um zu erfahren, wie du es deinstallieren kannst.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Esto debe desinstalarse antes de continuar. Haz click en 'Más información' para saber cómo desinstalarlo\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ceci doit être désinstallé avant de continuer. Cliquez sur « Plus d'informations » pour savoir comment le désinstaller.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Prima di continuare, il programma deve essere disinstallato. Clicca “Più informazioni” per scoprire come\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"계속하기 전 반드시 삭제해야 합니다. '추가 정보'를 클릭하여 삭제 방법을 알 수 있습니다.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Należy odinstalować przed kontynuowaniem. Kliknij „Więcej informacji”, aby dowiedzieć się, jak odinstalować\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Isto deve ser desinstalado antes de continuar. Clique em ‘Mais Informações’ para aprender como desinstalar.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sürdürme öncesi bunun kaldırılması gerekiyor. Nasıl kaldıracağınızı öğrenmek için “Daha Fazla Bilgi”ye tıklayın.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Щоб продовжити, необхідно це видалити. Натисніть «Більше інформації», щоб дізнатися, як це видалити.\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"اسے جاری رکھنے سے پہلے ان انسٹال کرنا ہوگا۔ مزید معلومات کے لیے 'مزید معلومات' پر کلک کریں۔\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"必须先卸载才能继续。点击“更多信息”了解如何卸载它。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"必須先解除安裝才能繼續。請點擊「更多資訊」了解如何解除安裝。\"\n          }\n        }\n      }\n    },\n    \"Time stamp: %@\" : {\n      \"comment\" : \"Time stamp: %@\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zeitstempel: %@\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Marca de tiempo: %@\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Horodatage : %@\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Marca temporale: %@\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"타임 스탬프: %@\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sygnatura czasowa: %@\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Registro da hora: %@\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zaman damgası: %@\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Мітка часу: %@\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ٹائم اسٹیمپ: %@\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"时间戳：%@\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"時間戳：%@\"\n          }\n        }\n      }\n    },\n    \"Uninstall\" : {\n      \"comment\" : \"Uninstall\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Deinstallieren\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desinstalar\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Désinstaller\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Disinstalla\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"삭제\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Odinstaluj\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desinstalar\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kaldır\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Видалити\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"انسٹال کریں\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"卸载\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"解除安裝\"\n          }\n        }\n      }\n    },\n    \"Uninstall LuLu?\" : {\n      \"comment\" : \"Uninstall LuLu?\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu deinstallieren?\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desinstalar LuLu?\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Désinstaller LuLu ?\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Disinstalla LuLu?\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu를 삭제할까요?\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Odinstalować LuLu?\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desinstalar LuLu?\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LuLu kaldırılsın mı?\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Видалити LuLu?\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"لولو کو ان انسٹال کریں؟\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"卸载LuLu ？\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"解除安裝 LuLu？\"\n          }\n        }\n      }\n    },\n    \"unknown\" : {\n      \"comment\" : \"unknown\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"unbekannt\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"desconocido\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"inconnu\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"sconosciuto\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"알 수 없음\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"nieznany\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desconhecido\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"bilinmiyor\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"невідомий\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"نامعلوم\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"未知\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"未知\"\n          }\n        }\n      }\n    },\n    \"Update\" : {\n      \"comment\" : \"Update\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Update\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Actualizar\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mise à jour\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aggiorna\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"업데이트\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aktualizacja\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Atualização\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Güncelle\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Оновити\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"اپ ڈیٹ\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"更新\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"更新\"\n          }\n        }\n      }\n    },\n    \"Update available, but isn't supported on macOS %ld.%ld\" : {\n      \"comment\" : \"Update available, but isn't supported on macOS %ld.%ld\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Update verfügbar, wird jedoch auf macOS %ld.%ld nicht unterstützt.\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"new\",\n            \"value\" : \"Update available, but isn't supported on macOS %1$ld.%2$ld\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Actualización disponible, pero no es compatible con macOS %ld.%ld\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mise à jour disponible, mais non prise en charge sur macOS %ld.%ld\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aggiornamento disponibile, ma non supportato su macOS %ld.%ld\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"업데이트를 사용할 수 있으나, macOS %ld.%ld에서는 지원되지 않습니다.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aktualizacja jest dostępna, ale nie jest obsługiwana w macOS %ld.%ld.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Atualização disponível, mas não é compatível com o macOS %ld.%ld\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Güncelleme kullanılabilir; ancak macOS %ld.%ld üzerinde desteklenmiyor.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Доступне оновлення, але воно не підтримується в macOS %ld.%ld\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"اپ ڈیٹ دستیاب ہے، لیکن macOS %1$ld.%2$ld پر تعاون یافتہ نہیں ہے۔\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"有可用更新，但不支持 macOS %ld.%ld\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"有可用更新，但不支持在 macOS %ld.%ld 上运行\"\n          }\n        }\n      }\n    },\n    \"User-specified Programs (manually added, or in response to an alert)\" : {\n      \"comment\" : \"User-specified Programs (manually added, or in response to an alert)\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vom Benutzer festgelegte Programme (manuell hinzugefügt oder als Reaktion auf eine Mitteilung)\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Programas especificados por el usuario (agregados manualmente, o en respuesta a una alerta)\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Programmes spécifiés par l'utilisateur (ajoutés manuellement ou en réponse à une alerte)\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Programmi specificati dall'utente (aggiunti manualmente o in risposta a un avviso)\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"사용자 지정 프로그램 (수동 또는 경고 창에 의해 추가됨)\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Programy określone przez użytkownika (dodane ręcznie lub w odpowiedzi na alert)\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Programas especificados pelo usuário (adicionados manualmente, ou em resposta à um alerta)\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kullanıcı tanımlı programlar (elle veya bir ikâza yönelik eklenir)\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Програми, вказані користувачем (додані вручну або у відповідь на сповіщення)\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"صارف کے ذریعہ مخصوص پروگرامز (مینیول طور پر شامل کیے گئے ہیں، یا انتباہ کے جواب میں)\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"用户指定的程序（手动添加或响应警报）\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"使用者指定的程式（手動新增或因警告而加入）\"\n          }\n        }\n      }\n    },\n    \"Version: %@\" : {\n      \"comment\" : \"Version: %@\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Version: %@\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Versión: %@\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Version : :@\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Versione: %@\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"버전: %@\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wersja: %@\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Versão: %@\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sürüm: %@\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Версія: %@\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ورژن: %@\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"版本: %@\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"版本：%@\"\n          }\n        }\n      }\n    },\n    \"Waiting for Network Extension Approval\" : {\n      \"comment\" : \"Waiting for Network Extension Approval\",\n      \"localizations\" : {\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Warten auf Genehmigung der Netzwerkerweiterung\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Esperando la aprobación de la Extensión de Red\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"En attente de l'approbation de l'extension réseau\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"In attesa di approvazione per l’estensione di rete\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"네트워크 확장 프로그램 승인 대기 중\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Oczekiwanie na zatwierdzenie rozszerzenia sieci\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aguardando aprovação da Extensão de Rede\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ağ genişletmesi onayı bekleniyor\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Очікується схвалення мережевого розширення\"\n          }\n        },\n        \"ur\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"نیٹ ورک ایکسٹینشن کی منظوری کا انتظار\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"等待网络扩展批准\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"正在等待網路延伸功能被核准\"\n          }\n        }\n      }\n    }\n  },\n  \"version\" : \"1.0\"\n}"
  },
  {
    "path": "LuLu/Shared/Rule.h",
    "content": "//\n//  file: Rule.h\n//  project: LuLu (shared)\n//  description: Rule object (header)\n//\n//  created by Patrick Wardle\n//  copyright (c) 2017 Objective-See. All rights reserved.\n//\n\n#ifndef Rule_h\n#define Rule_h\n\n@import OSLog;\n@import Foundation;\n\n@interface Rule : NSObject <NSSecureCoding>\n{\n    \n}\n\n/* PROPERTIES */\n\n//uuid\n@property(nonatomic, retain)NSString* uuid;\n\n//key\n@property(nonatomic, retain)NSString* key;\n\n// PROCESS/BINARY INFO\n\n//rule pid\n// only set if rule's duration is set to process lifetime\n@property(nonatomic, retain)NSNumber* pid;\n\n//path\n@property(nonatomic, retain)NSString* path;\n\n//flag for global rule\n@property(nonatomic, retain)NSNumber* isGlobal;\n\n//flag for directory rule\n@property(nonatomic, retain)NSNumber* isDirectory;\n\n//name\n@property(nonatomic, retain)NSString* name;\n\n//signing info\n@property(nonatomic, retain)NSDictionary* csInfo;\n\n//remote ip or url\n@property(nonatomic, retain)NSString* endpointAddr;\n\n//remote host\n@property(nonatomic, retain)NSString* endpointHost;\n\n//flag for endpoint addr\n@property BOOL isEndpointAddrRegex;\n\n//remote port\n@property(nonatomic, retain)NSString* endpointPort;\n\n//type\n// default, user, etc\n@property(nonatomic, retain)NSNumber* type;\n\n//protocol\n@property(nonatomic, retain)NSNumber* protocol;\n\n//is disabled\n@property(nonatomic, retain)NSNumber* isDisabled;\n\n// TIMESTAMPS\n\n//rule creation\n@property(nonatomic, retain)NSDate* creation;\n\n//rule expiration\n// only set if rule's duration is set to expire\n@property(nonatomic, retain)NSDate* expiration;\n\n\n// ACTION\n\n//action\n// allow / deny\n@property(nonatomic, retain)NSNumber* action;\n\n//action scope\n// process, endpoint, etc\n@property(nonatomic, retain)NSNumber* scope;\n\n\n/* METHODS */\n\n//init method\n-(id)init:(NSDictionary*)info;\n\n//matches a string?\n-(BOOL)matchesString:(NSString*)match;\n\n//matches a(nother) rule?\n-(BOOL)isEqualToRule:(Rule *)rule;\n\n//is rule temp?\n-(BOOL)isTemporary;\n\n//is rule user (created)\n-(BOOL)isUserCreated;\n\n//covert to dictionary\n-(NSMutableString*)toJSON;\n\n//make a rule obj from a dictioanary\n-(id)initFromJSON:(NSDictionary*)info;\n\n@end\n\n#endif /* Rule_h */\n"
  },
  {
    "path": "LuLu/Shared/Rule.m",
    "content": "//\n//  file: Rule.h\n//  project: LuLu (shared)\n//  description: Rule object (header)\n//\n//  created by Patrick Wardle\n//  copyright (c) 2020 Objective-See. All rights reserved.\n//\n\n#import \"Rule.h\"\n#import \"consts.h\"\n#import \"utilities.h\"\n\n#import <objc/runtime.h>\n\n/* GLOBALS */\n\n//log handle\nextern os_log_t logHandle;\n\n@implementation Rule\n\n@synthesize scope;\n@synthesize action;\n\n//init method\n-(id)init:(NSDictionary*)info\n{\n    //init super\n    if(self = [super init])\n    {\n        //url\n        NSURL* remoteURL = nil;\n        \n        //dbg msg\n        os_log_debug(logHandle, \"creating rule with: %{public}@\", info);\n        \n        //create UUID\n        self.uuid = [[NSUUID UUID] UUIDString];\n        \n        //init pid\n        // note: only set for temporary rules\n        if(YES == [info[KEY_DURATION_PROCESS] boolValue])\n        {\n            //set\n            self.pid = info[KEY_PROCESS_ID];\n        }\n        \n        //set creation\n        self.creation = [NSDate date];\n        \n        //init expiration\n        // though this won't (usually) be set\n        self.expiration = info[KEY_DURATION_EXPIRATION];\n        \n        //init path\n        self.path = info[KEY_PATH];\n        \n        //init name\n        self.name = (nil != info[KEY_PROCESS_NAME]) ? info[KEY_PROCESS_NAME] : getProcessName(0, self.path);\n        \n        //init signing info\n        self.csInfo = info[KEY_CS_INFO];\n        \n        //process scope (set via alert)\n        // set endpoint info to all ('*')\n        if( (nil != info[KEY_SCOPE]) &&\n            (ACTION_SCOPE_PROCESS == [info[KEY_SCOPE] intValue]) )\n        {\n            //dbg msg\n            os_log_debug(logHandle, \"rule info has 'KEY_SCOPE' set to 'ACTION_SCOPE_PROCESS'\");\n            \n            //any addr\n            self.endpointAddr = VALUE_ANY;\n            \n            //any port\n            self.endpointPort = VALUE_ANY;\n        }\n        //other use endpoint info\n        // or if nil, set to all ('*')\n        else\n        {\n            //init addr\n            // nil? default to all ('*')\n            self.endpointAddr = (nil != info[KEY_ENDPOINT_ADDR]) ? info[KEY_ENDPOINT_ADDR] : VALUE_ANY;\n            \n            //is endpoint addr a regex?\n            self.isEndpointAddrRegex = [info[KEY_ENDPOINT_ADDR_IS_REGEX] boolValue];\n            \n            //init port\n            // nil? default to all ('*')\n            self.endpointPort = (nil != info[KEY_ENDPOINT_PORT]) ? info[KEY_ENDPOINT_PORT] : VALUE_ANY;\n        }\n        \n        //init URL obj (w/ scheme)\n        // so we can extract a host\n        if(YES != [self.endpointAddr isEqualToString:VALUE_ANY])\n        {\n            //init url w/ scheme\n            if(YES != [self.endpointAddr hasPrefix:@\"http\"])\n            {\n                //init url\n                remoteURL = [NSURL URLWithString:[NSString stringWithFormat:@\"http://%@\", self.endpointAddr]];\n            }\n            //no scheme needed\n            else\n            {\n                //init url\n                remoteURL = [NSURL URLWithString:self.endpointAddr];\n            }\n            \n            //now with URL obj, get host name\n            self.endpointHost = remoteURL.host;\n        }\n        \n        //set proto\n        self.protocol = info[KEY_PROTOCOL];\n    \n        //set type\n        self.type = info[KEY_TYPE];\n        \n        //init action\n        self.action = info[KEY_ACTION];\n        \n        //now, generate key\n        if(nil != info[KEY_KEY])\n        {\n            //set\n            self.key = info[KEY_KEY];\n        }\n        //generate key\n        else\n        {\n            //generate\n            self.key = [self generateKey];\n        }\n    }\n        \n    return self;\n}\n\n//generate key\n// note: this matches process' generate key algo\n-(NSString*)generateKey\n{\n    //id\n    NSString* key = nil;\n    \n    //signer\n    NSInteger signer = None;\n    \n    //cs info?\n    if(nil != self.csInfo)\n    {\n        //extract signer\n        signer = [self.csInfo[KEY_CS_SIGNER] intValue];\n        \n        //apple/app store\n        // just use cs id\n        if( (Apple == signer) ||\n            (AppStore == signer) )\n        {\n            //set key\n            key = self.csInfo[KEY_CS_ID];\n        }\n        \n        //dev id?\n        // use cs id + (leaf) signer\n        else if(DevID == signer)\n        {\n            //check for cs id/auths\n            if( (0 != [self.csInfo[KEY_CS_ID] length]) &&\n                (0 != [self.csInfo[KEY_CS_AUTHS] count]) )\n            {\n                //set\n                key = [NSString stringWithFormat:@\"%@:%@\", self.csInfo[KEY_CS_ID], [self.csInfo[KEY_CS_AUTHS] firstObject]];\n            }\n        }\n    }\n    \n    //no valid cs info, etc\n    // just use item's path\n    if(0 == key.length)\n    {\n        //set\n        key = self.path;\n    }\n    \n    //dbg msg\n    os_log_debug(logHandle, \"generated rule key: %{public}@\", key);\n\n    return key;\n}\n\n//is rule global?\n-(NSNumber*)isGlobal\n{\n    //first time?\n    // init and set\n    if(nil == _isGlobal)\n    {\n        //set\n        _isGlobal = [NSNumber numberWithBool:[self.path isEqualToString:VALUE_ANY]];\n    }\n    \n    return _isGlobal;\n}\n\n//is rule temporary?\n// ...just if its duration is set to process lifetime (e.g. has a pid)\n-(BOOL)isTemporary\n{\n    return (nil != self.pid);\n}\n\n//is rule user (created)?\n-(BOOL)isUserCreated\n{\n    return (self.type.intValue == RULE_TYPE_USER);\n}\n\n//is rule directory?\n-(NSNumber*)isDirectory\n{\n    //first time?\n    // init and set\n    if(nil == _isDirectory)\n    {\n        //set\n        _isDirectory = [NSNumber numberWithBool:((YES == [self.path hasPrefix:@\"/\"]) && (YES == [self.path hasSuffix:@\"/*\"]))];\n    }\n    \n    return _isDirectory;\n}\n\n//required as we support secure coding\n+(BOOL)supportsSecureCoding\n{\n    return YES;\n}\n\n//init with coder\n-(id)initWithCoder:(NSCoder *)decoder\n{\n    //super\n    if(self = [super init])\n    {\n        //decode rule object\n        \n        self.key = [decoder decodeObjectOfClass:[NSString class] forKey:NSStringFromSelector(@selector(key))];\n        self.uuid = [decoder decodeObjectOfClass:[NSString class] forKey:NSStringFromSelector(@selector(uuid))];\n        \n        self.pid = [decoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(pid))];\n        self.path = [decoder decodeObjectOfClass:[NSString class] forKey:NSStringFromSelector(@selector(path))];\n        self.name = [decoder decodeObjectOfClass:[NSString class] forKey:NSStringFromSelector(@selector(name))];\n        self.csInfo = [decoder decodeObjectOfClasses:[NSSet setWithArray:@[[NSDictionary class], [NSArray class], [NSString class], [NSNumber class]]] forKey:NSStringFromSelector(@selector(csInfo))];\n        \n        self.isEndpointAddrRegex = [decoder decodeBoolForKey:NSStringFromSelector(@selector(isEndpointAddrRegex))];\n        self.endpointAddr = [decoder decodeObjectOfClass:[NSString class] forKey:NSStringFromSelector(@selector(endpointAddr))];\n        self.endpointHost = [decoder decodeObjectOfClass:[NSString class] forKey:NSStringFromSelector(@selector(endpointHost))];\n        self.endpointPort = [decoder decodeObjectOfClass:[NSString class] forKey:NSStringFromSelector(@selector(endpointPort))];\n        \n        self.type = [decoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(type))];\n        self.scope = [decoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(scope))];\n        self.action = [decoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(action))];\n        \n        self.isDisabled = [decoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(isDisabled))];\n        \n        self.creation = [decoder decodeObjectOfClass:[NSDate class] forKey:NSStringFromSelector(@selector(creation))];\n        self.expiration = [decoder decodeObjectOfClass:[NSDate class] forKey:NSStringFromSelector(@selector(expiration))];\n    }\n    \n    return self;\n}\n\n//encode with coder\n-(void)encodeWithCoder:(NSCoder *)encoder\n{\n    //encode rule object\n    \n    [encoder encodeObject:self.key forKey:NSStringFromSelector(@selector(key))];\n    [encoder encodeObject:self.uuid forKey:NSStringFromSelector(@selector(uuid))];\n    \n    [encoder encodeObject:self.pid forKey:NSStringFromSelector(@selector(pid))];\n    [encoder encodeObject:self.path forKey:NSStringFromSelector(@selector(path))];\n    [encoder encodeObject:self.name forKey:NSStringFromSelector(@selector(name))];\n    [encoder encodeObject:self.csInfo forKey:NSStringFromSelector(@selector(csInfo))];\n    \n    [encoder encodeObject:self.endpointAddr forKey:NSStringFromSelector(@selector(endpointAddr))];\n    [encoder encodeObject:self.endpointHost forKey:NSStringFromSelector(@selector(endpointHost))];\n    [encoder encodeObject:self.endpointPort forKey:NSStringFromSelector(@selector(endpointPort))];\n    [encoder encodeBool:self.isEndpointAddrRegex forKey:NSStringFromSelector(@selector(isEndpointAddrRegex))];\n    \n    [encoder encodeObject:self.type forKey:NSStringFromSelector(@selector(type))];\n    [encoder encodeObject:self.scope forKey:NSStringFromSelector(@selector(scope))];\n    [encoder encodeObject:self.action forKey:NSStringFromSelector(@selector(action))];\n    \n    [encoder encodeObject:self.isDisabled forKey:NSStringFromSelector(@selector(isDisabled))];\n\n    [encoder encodeObject:self.creation forKey:NSStringFromSelector(@selector(creation))];\n    [encoder encodeObject:self.expiration forKey:NSStringFromSelector(@selector(expiration))];\n\n    return;\n}\n\n//matches a string?\n// used for filtering in UI\n-(BOOL)matchesString:(NSString*)match\n{\n    //match\n    BOOL matches = NO;\n    \n    //rule action (as string)\n    NSString* action = nil;\n    \n    //init w/ allow\n    if(RULE_STATE_ALLOW == self.action.integerValue)\n    {\n        action = NSLocalizedString(@\"Allow\", \"@Allow\");\n    }\n    //init w/ block\n    else if(RULE_STATE_BLOCK == self.action.integerValue)\n    {\n        action = NSLocalizedString(@\"Block\", @\"Block\");\n    }\n    \n    //check name, path\n    if( (YES == [self.name localizedCaseInsensitiveContainsString:match]) ||\n        (YES == [self.path localizedCaseInsensitiveContainsString:match]) )\n    {\n        //match\n        matches = YES;\n        goto bail;\n    }\n    \n    //check pid\n    if( (nil != self.pid) &&\n        (YES == [self.pid.stringValue containsString:match]) )\n    {\n        //match\n        matches = YES;\n        goto bail;\n    }\n    \n    //check cs id\n    if( (nil != self.csInfo[KEY_CS_ID]) &&\n        (YES == [self.csInfo[KEY_CS_ID] localizedCaseInsensitiveContainsString:match]) )\n    {\n        //match\n        matches = YES;\n        goto bail;\n    }\n    \n    //endpoint addr/port\n    if( (YES == [self.endpointAddr localizedCaseInsensitiveContainsString:match]) ||\n        (YES == [self.endpointPort localizedCaseInsensitiveContainsString:match]) )\n    {\n        //match\n        matches = YES;\n        goto bail;\n    }\n    \n    //endpoint addr ('any')\n    if( (YES == [self.endpointAddr isEqualToString:VALUE_ANY]) &&\n        (YES == [match isEqualToString:NSLocalizedString(@\"any address\", @\"any address\")]) )\n    {\n        //match\n        matches = YES;\n        goto bail;\n    }\n    \n    //endpoint port ('any')\n    if( (YES == [self.endpointPort isEqualToString:VALUE_ANY]) &&\n        (YES == [match isEqualToString:NSLocalizedString(@\"any port\", @\"any port\")]) )\n    {\n        //match\n        matches = YES;\n        goto bail;\n    }\n    \n    //check state\n    if( (nil != action) &&\n        (YES == [action localizedCaseInsensitiveContainsString:match]) )\n    {\n        //match\n        matches = YES;\n        goto bail;\n    }\n    \nbail:\n    \n    return matches;\n}\n\n//matches a(nother) rule?\n-(BOOL)isEqualToRule:(Rule *)rule\n{\n    return [self.uuid isEqualToString:rule.uuid];\n}\n\n//override description method\n// allows rules to be 'pretty-printed'\n-(NSString*)description\n{\n    id pid = @\"all\";\n    id isDisabled = @NO;\n    id expiration = @\"never\";\n    \n    //has pid?\n    if(self.pid)\n    {\n        pid = self.pid;\n    }\n    \n    //has expiration?\n    if(self.expiration)\n    {\n        expiration = self.expiration;\n    }\n    \n    //disabled?\n    if(self.isDisabled) {\n        isDisabled = self.isDisabled;\n    }\n    \n    //just serialize\n    return [NSString stringWithFormat:@\"RULE: pid: %@, path: %@, name: %@, endpoint addr: %@, endpoint port: %@, action: %@, type: %@, disabled: %@, creation: %@, expiration: %@\", pid, self.path, self.name, self.endpointAddr, self.endpointPort, self.action, self.type, isDisabled, self.creation, expiration];\n}\n\n//covert rule to dictionary\n// needed for conversion to JSON\n// note: temporary properties (such as pid) not included\n-(NSMutableString*)toJSON\n{\n    //json\n    NSMutableString* json = nil;\n    \n    //escaped\n    NSString* escaped = nil;\n    \n    //date formatter\n    NSDateFormatter* dateFormatter = nil;\n    \n    //init formatter\n    // format: ISO 8601 format\n    dateFormatter = [[NSDateFormatter alloc] init];\n    [dateFormatter setDateFormat:@\"yyyy-MM-dd'T'HH:mm:ssZ\"];\n    \n    //init\n    json = [NSMutableString string];\n    \n    //key\n    [json appendFormat:@\"\\\"%@\\\" : \\\"%@\\\",\", NSStringFromSelector(@selector(key)), self.key];\n    \n    //uuid\n    [json appendFormat:@\"\\\"%@\\\" : \\\"%@\\\",\", NSStringFromSelector(@selector(uuid)), self.uuid];\n    \n    //path\n    escaped = toEscapedJSON(self.path);\n    if(nil != escaped)\n    {\n        [json appendFormat:@\"\\\"%@\\\" : %@,\", NSStringFromSelector(@selector(path)), escaped];\n    }\n    \n    //name\n    escaped = toEscapedJSON(self.name);\n    if(nil != escaped)\n    {\n        [json appendFormat:@\"\\\"%@\\\" : %@,\", NSStringFromSelector(@selector(name)), escaped];\n    }\n    \n    escaped = toEscapedJSON(self.endpointAddr);\n    if(nil != escaped)\n    {\n        [json appendFormat:@\"\\\"%@\\\" : %@,\", NSStringFromSelector(@selector(endpointAddr)), escaped];\n    }\n    \n    if(nil != self.endpointHost)\n    {\n        escaped = toEscapedJSON(self.endpointHost);\n        if(nil != escaped)\n        {\n            [json appendFormat:@\"\\\"%@\\\" : %@,\", NSStringFromSelector(@selector(endpointHost)), escaped];\n        }\n    }\n    \n    //creation\n    if(nil != self.creation)\n    {\n        [json appendFormat:@\"\\\"%@\\\" : \\\"%@\\\",\", NSStringFromSelector(@selector(creation)), [dateFormatter stringFromDate:self.creation]];\n    }\n    \n    //expiration\n    if(nil != self.expiration)\n    {\n        [json appendFormat:@\"\\\"%@\\\" : \\\"%@\\\",\", NSStringFromSelector(@selector(expiration)), [dateFormatter stringFromDate:self.expiration]];\n    }\n\n    //port\n    [json appendFormat:@\"\\\"%@\\\" : \\\"%@\\\",\", NSStringFromSelector(@selector(endpointPort)), self.endpointPort];\n    \n    //is regex\n    [json appendFormat:@\"\\\"%@\\\" : %d,\", NSStringFromSelector(@selector(isEndpointAddrRegex)), self.isEndpointAddrRegex];\n\n    //type\n    [json appendFormat:@\"\\\"%@\\\" : %d,\", NSStringFromSelector(@selector(type)), self.type.intValue];\n    \n    //disabled\n    if(nil != self.isDisabled)\n    {\n        [json appendFormat:@\"\\\"%@\\\" : %d,\", NSStringFromSelector(@selector(isDisabled)), self.isDisabled.intValue];\n    }\n    \n    //scope\n    [json appendFormat:@\"\\\"%@\\\" : %d,\", NSStringFromSelector(@selector(scope)), self.scope.intValue];\n    \n    //action\n    [json appendFormat:@\"\\\"%@\\\" : %d,\", NSStringFromSelector(@selector(action)), self.action.intValue];\n    \n    //cs info\n    // dictionary...\n    if(nil != self.csInfo)\n    {\n        [json appendFormat:@\"\\\"%@\\\" : {\", NSStringFromSelector(@selector(csInfo))];\n        \n        //convert each key/value pair\n        for(NSString* key in self.csInfo)\n        {\n            //extract value\n            id value = self.csInfo[key];\n            \n            //string?\n            if(YES == [value isKindOfClass:[NSString class]])\n            {\n                escaped = toEscapedJSON(value);\n                if(nil != escaped)\n                {\n                    //append\n                    [json appendFormat:@\"\\\"%@\\\" : %@,\", key, escaped];\n                }\n            }\n            \n            //number?\n            if(YES == [value isKindOfClass:[NSNumber class]])\n            {\n                //append\n                [json appendFormat:@\"\\\"%@\\\" : %d,\", key, [value intValue]];\n            }\n            \n            //array?\n            if(YES == [value isKindOfClass:[NSArray class]])\n            {\n                //append\n                [json appendFormat:@\"\\\"%@\\\" : [\", key];\n                \n                //add each item\n                for(id item in value)\n                {\n                    //string?\n                    if(YES == [item isKindOfClass:[NSString class]])\n                    {\n                        escaped = toEscapedJSON(item);\n                        if(nil != escaped)\n                        {\n                            //append\n                            [json appendFormat:@\"%@,\", escaped];\n                        }\n                    }\n                    else\n                    {\n                        [json appendFormat:@\"\\\"%@\\\",\", item];\n                    }\n                }\n                \n                //remove last ','\n                if(YES == [json hasSuffix:@\",\"])\n                {\n                    //remove\n                    [json deleteCharactersInRange:NSMakeRange(json.length-1, 1)];\n                }\n                \n                //end\n                [json appendFormat:@\"],\"];\n            }\n        }\n        \n        //remove last ','\n        if(YES == [json hasSuffix:@\",\"])\n        {\n            //remove\n            [json deleteCharactersInRange:NSMakeRange(json.length-1, 1)];\n        }\n        \n        //end\n        [json appendFormat:@\"}\"];\n    }\n    \n    //remove last ','\n    if(YES == [json hasSuffix:@\",\"])\n    {\n        //remove\n        [json deleteCharactersInRange:NSMakeRange(json.length-1, 1)];\n    }\n    \n    return json;\n}\n\n//make a rule obj from a dictioanary\n-(id)initFromJSON:(NSDictionary*)info\n{\n    id value = nil;\n    \n    //date formatter\n    NSDateFormatter* dateFormatter = nil;\n    \n    //init formatter\n    // format: ISO 8601 format\n    dateFormatter = [[NSDateFormatter alloc] init];\n    [dateFormatter setDateFormat:@\"yyyy-MM-dd'T'HH:mm:ssZ\"];\n    \n    //dbg msg\n    //os_log_debug(logHandle, \"method '%s' invoked\", __PRETTY_FUNCTION__);\n    \n    //super\n    if(self = [super init])\n    {\n        //init + sanity checks\n        self.key = info[NSStringFromSelector(@selector(key))];\n        if(YES != [self.key isKindOfClass:[NSString class]])\n        {\n            //err msg\n            os_log_error(logHandle, \"ERROR: 'key' should be a string, not %@\", [self.key class]);\n            \n            self = nil;\n            goto bail;\n        }\n        \n        self.uuid = info[NSStringFromSelector(@selector(uuid))];\n        if(YES != [self.uuid isKindOfClass:[NSString class]])\n        {\n            //err msg\n            os_log_error(logHandle, \"ERROR: 'uuid' should be a string, not %@\", [self.uuid class]);\n            \n            self = nil;\n            goto bail;\n        }\n        \n        self.path = info[NSStringFromSelector(@selector(path))];\n        if(YES != [self.path isKindOfClass:[NSString class]])\n        {\n            //err msg\n            os_log_error(logHandle, \"ERROR: 'path' should be a string, not %@\", [self.path class]);\n            \n            self = nil;\n            goto bail;\n        }\n        \n        self.name = info[NSStringFromSelector(@selector(name))];\n        if(YES != [self.name isKindOfClass:[NSString class]])\n        {\n            //err msg\n            os_log_error(logHandle, \"ERROR: 'name' should be a string, not %@\", [self.name class]);\n            \n            self = nil;\n            goto bail;\n        }\n        \n        self.csInfo = info[NSStringFromSelector(@selector(csInfo))];\n        if( (nil != self.csInfo) &&\n            (YES != [self.csInfo isKindOfClass:[NSDictionary class]]) )\n        {\n            //err msg\n            os_log_error(logHandle, \"ERROR: 'csInfo' should be a dictionary, not %@\", [self.csInfo class]);\n            \n            self = nil;\n            goto bail;\n        }\n\n        self.endpointAddr = info[NSStringFromSelector(@selector(endpointAddr))];\n        if(YES != [self.endpointAddr isKindOfClass:[NSString class]])\n        {\n            //err msg\n            os_log_error(logHandle, \"ERROR: 'endpointAddr' should be a string, not %@\", [self.endpointAddr class]);\n            \n            self = nil;\n            goto bail;\n        }\n        \n        self.endpointHost = info[NSStringFromSelector(@selector(endpointHost))];\n        if( (nil != self.endpointHost) &&\n            (YES != [self.endpointHost isKindOfClass:[NSString class]]) )\n        {\n            //err msg\n            os_log_error(logHandle, \"ERROR: 'endpointHost' should be a string, not %@\", [self.endpointHost class]);\n            \n            self = nil;\n            goto bail;\n        }\n        \n        self.endpointPort = info[NSStringFromSelector(@selector(endpointPort))];\n        if(YES != [self.endpointPort isKindOfClass:[NSString class]])\n        {\n            //err msg\n            os_log_error(logHandle, \"ERROR: 'endpointPort' should be a string, not %@\", [self.endpointPort class]);\n            \n            self = nil;\n            goto bail;\n        }\n        \n        self.isEndpointAddrRegex = [info[NSStringFromSelector(@selector(isEndpointAddrRegex))] boolValue];\n        \n        self.type = info[NSStringFromSelector(@selector(type))];\n        if([self.type isKindOfClass:[NSString class]]) {\n            self.type = @([(NSString*)self.type integerValue]);\n        }\n        \n        if(YES != [self.type isKindOfClass:[NSNumber class]])\n        {\n            //err msg\n            os_log_error(logHandle, \"ERROR: 'type' should be a number, not %@\", [self.type class]);\n            \n            self = nil;\n            goto bail;\n        }\n        \n        self.scope = info[NSStringFromSelector(@selector(scope))];\n        if([self.scope isKindOfClass:[NSString class]]) {\n            self.scope = @([(NSString*)self.scope integerValue]);\n        }\n        \n        if(YES != [self.scope isKindOfClass:[NSNumber class]])\n        {\n            //err msg\n            os_log_error(logHandle, \"ERROR: 'scope' should be a number, not %@\", [self.scope class]);\n            \n            self = nil;\n            goto bail;\n        }\n        \n        self.action = info[NSStringFromSelector(@selector(action))];\n        if([self.action isKindOfClass:[NSString class]]) {\n            self.action = @([(NSString*)self.action integerValue]);\n        }\n        \n        if(YES != [self.action isKindOfClass:[NSNumber class]])\n        {\n            //err msg\n            os_log_error(logHandle, \"ERROR: 'action' should be a number, not %@\", [self.action class]);\n            \n            self = nil;\n            goto bail;\n        }\n        \n        //disabled?\n        // note: optional\n        self.isDisabled = info[NSStringFromSelector(@selector(isDisabled))];\n        if(self.isDisabled && [self.isDisabled isKindOfClass:[NSString class]]) {\n            self.isDisabled = @([(NSString*)self.isDisabled integerValue]);\n        }\n        \n        if(self.isDisabled && ![self.isDisabled isKindOfClass:[NSNumber class]])\n        {\n            //err msg\n            os_log_error(logHandle, \"ERROR: 'disabled' should be a number or nil, not %@\", [self.isDisabled class]);\n            \n            self = nil;\n            goto bail;\n        }\n        \n        //creation (date)\n        value = info[NSStringFromSelector(@selector(creation))];\n        if(value) {\n            \n            if(![value isKindOfClass:[NSString class]]) {\n                //err msg\n                os_log_error(logHandle, \"ERROR: 'creation' should be a string, not %@\", [value class]);\n                \n                self = nil;\n                goto bail;\n            }\n            \n            self.creation = [dateFormatter dateFromString:value];\n            if(!self.creation) {\n                //err msg\n                os_log_error(logHandle, \"ERROR: 'creation' date string is invalid: %@\", value);\n                \n                self = nil;\n                goto bail;\n            }\n        }\n        \n        //expiration\n        value = info[NSStringFromSelector(@selector(expiration))];\n        if(value) {\n            \n            if(![value isKindOfClass:[NSString class]]) {\n                //err msg\n                os_log_error(logHandle, \"ERROR: 'expiration' should be a string, not %@\", [value class]);\n                \n                self = nil;\n                goto bail;\n            }\n            \n            self.expiration = [dateFormatter dateFromString:value];\n            if(!self.expiration) {\n                //err msg\n                os_log_error(logHandle, \"ERROR: 'expiration' date string is invalid: %@\", value);\n                \n                self = nil;\n                goto bail;\n            }\n        }\n    }\n    \nbail:\n        \n    return self;\n}\n\n@end\n"
  },
  {
    "path": "LuLu/Shared/XPCDaemonProto.h",
    "content": "//\n//  file: XPCDaemonProtocol.h\n//  project: LuLu (shared)\n//  description: methods exported by the daemon\n//\n//  created by Patrick Wardle\n//  copyright (c) 2018 Objective-See. All rights reserved.\n//\n\n@import Foundation;\n\n@protocol XPCDaemonProtocol\n\n//get preferences\n-(void)getPreferences:(void (^)(NSDictionary*))reply;\n\n//update preferences\n-(void)updatePreferences:(NSDictionary*)preferences reply:(void (^)(NSDictionary*))reply;\n\n//get rules\n-(void)getRules:(void (^)(NSData*))reply;\n\n//add rule\n-(void)addRule:(NSDictionary*)info;\n\n//disable (or re-enable) rule\n-(void)toggleRule:(NSString*)key rule:(NSString*)uuid state:(NSNumber*)state;\n\n//delete rule\n-(void)deleteRule:(NSString*)key rule:(NSString*)uuid;\n\n//import rules\n-(void)importRules:(NSData*)newRules userOnly:(BOOL)userOnly result:(void (^)(BOOL))reply;\n\n//cleanup rules\n-(void)cleanupRules:(BOOL)fule reply:(void (^)(NSInteger))reply;\n\n//get current profile\n-(void)getCurrentProfile:(void (^)(NSString*))profile;\n\n//get list of profiles\n-(void)getProfiles:(void (^)(NSArray*))reply;\n\n//add profile\n-(void)addProfile:(NSString*)name preferences:(NSDictionary*)preferences reply:(void (^)(BOOL))reply;\n\n//delete profile\n-(void)deleteProfile:(NSString*)name reply:(void (^)(BOOL))reply;\n\n//set profile\n-(void)setProfile:(NSString*)name reply:(void (^)(BOOL))reply;\n\n//uninstall\n-(void)uninstall:(void (^)(BOOL))reply;\n\n@end\n"
  },
  {
    "path": "LuLu/Shared/XPCUserProto.h",
    "content": "//\n//  file: XPCUserProtocol\n//  project: LuLu (shared)\n//  description: protocol for talking to the user (header)\n//\n//  created by Patrick Wardle\n//  copyright (c) 2018 Objective-See. All rights reserved.\n//\n\n@import Foundation;\n\n@protocol XPCUserProtocol\n\n//rules changed\n-(void)rulesChanged;\n\n//show an alert\n-(void)alertShow:(NSDictionary*)alert reply:(void (^)(NSDictionary*))reply;\n\n@end\n\n"
  },
  {
    "path": "LuLu/Shared/consts.h",
    "content": "//\n//  file: consts.h\n//  project: lulu (shared)\n//  description: #defines and what not\n//\n//  created by Patrick Wardle\n//  copyright (c) 2017 Objective-See. All rights reserved.\n//\n\n#ifndef consts_h\n#define consts_h\n\n//signers\nenum Signer{None, Apple, AppStore, DevID, AdHoc};\n\n//patreon url\n#define PATREON_URL @\"https://www.patreon.com/join/objective_see\"\n\n//vendor id string\n#define OBJECTIVE_SEE_VENDOR \"com.objectiveSee\"\n\n//bundle ID\n#define BUNDLE_ID \"com.objective-see.lulu\"\n\n//extension bundle ID\n#define EXT_BUNDLE_ID @\"com.objective-see.lulu.extension\"\n\n//main app bundle id\n#define APP_ID @\"com.objective-see.lulu.app\"\n\n//signing auth\n#define SIGNING_AUTH @\"Developer ID Application: Objective-See, LLC (VBG97UB4TA)\"\n\n//firewall event: new flow\n#define LULU_EVENT @\"com.objective-see.lulu.event\"\n\n//lulu service\n#define LULU_SERVICE_NAME \"com_objective_see_firewall\"\n\n//install directory\n#define INSTALL_DIRECTORY @\"/Library/Objective-See/LuLu\"\n\n//preferences file\n#define PREFS_FILE @\"preferences.plist\"\n\n//rules file\n#define RULES_FILE @\"rules.plist\"\n\n//(old) rules file\n#define RULES_FILE_V1 @\"rules_v1.plist\"\n\n//client no status\n#define STATUS_CLIENT_UNKNOWN -1\n\n//client disabled\n#define STATUS_CLIENT_DISABLED 0\n\n//client enabled\n#define STATUS_CLIENT_ENABLED 1\n\n//daemon mach name\n#define DAEMON_MACH_SERVICE @\"VBG97UB4TA.com.objective-see.lulu\"\n\n//rule state; not found\n#define RULE_STATE_NOT_FOUND -1\n\n//rule state; block\n#define RULE_STATE_BLOCK 0\n\n//rule state; allow\n#define RULE_STATE_ALLOW 1\n\n//product version url\n#define PRODUCT_VERSIONS_URL @\"https://objective-see.org/products.json\"\n\n//app name\n#define PRODUCT_NAME @\"LuLu\"\n\n//product url\n#define PRODUCT_URL @\"https://objective-see.org/products/lulu.html\"\n\n//error(s) url\n#define ERRORS_URL @\"https://objective-see.org/errors.html\"\n\n//support us button tag\n#define BUTTON_SUPPORT_US 100\n\n//more info button tag\n#define BUTTON_MORE_INFO 101\n\n//install cmd\n#define CMD_INSTALL @\"-install\"\n\n//uninstall cmd\n#define CMD_UNINSTALL @\"-uninstall\"\n\n//flag to uninstall\n#define ACTION_UNINSTALL_FLAG 0\n\n//flag to install\n#define ACTION_INSTALL_FLAG 1\n\n//flag for partial uninstall\n// leave preferences file, etc.\n#define UNINSTALL_PARTIAL 0\n\n//flag for full uninstall\n#define UNINSTALL_FULL 1\n\n//add rule, block\n#define BUTTON_BLOCK 0\n\n//add rule, allow\n#define BUTTON_ALLOW 1\n\n//login item name\n#define LOGIN_ITEM_NAME @\"LuLu Helper\"\n\n//prefs\n// disabled status\n#define PREF_IS_DISABLED @\"disabled\"\n\n//prefs\n// passive mode, & rules/action\n#define PREF_PASSIVE_MODE @\"passiveMode\"\n#define PREF_PASSIVE_MODE_RULES @\"passiveModeRules\"\n#define PREF_PASSIVE_MODE_ACTION @\"passiveModeAction\"\n\n//index of allow/block in passive mode action\n#define PREF_PASSIVE_MODE_ALLOW 0\n#define PREF_PASSIVE_MODE_BLOCK 1\n\n//index of no/yes in passive mode action\n#define PREF_PASSIVE_MODE_RULES_NO 0\n#define PREF_PASSIVE_MODE_RULES_YES 1\n\n//prefs\n// block mode\n#define PREF_BLOCK_MODE @\"blockMode\"\n\n//prefs\n// icon mode\n#define PREF_NO_ICON_MODE @\"noIconMode\"\n\n//prefs\n// no VT mode\n#define PREF_NO_VT_MODE @\"noVTMode\"\n\n//prefs\n// update mode\n#define PREF_NO_UPDATE_MODE @\"noupdateMode\"\n\n//prefs\n// allow all apple binaries\n#define PREF_ALLOW_APPLE @\"allowApple\"\n\n//prefs\n// allow all installed\n#define PREF_ALLOW_INSTALLED @\"allowInstalled\"\n\n//prefs\n// allow dns traffic\n#define PREF_ALLOW_DNS @\"allowDNS\"\n\n//prefs\n// allow localhost traffic\n#define PREF_ALLOW_LOCALHOST @\"allowLocalHost\"\n\n//prefs\n// allow simulator apps\n#define PREF_ALLOW_SIMULATOR @\"allowSimulatorApps\"\n\n//use global block list\n#define PREF_USE_BLOCK_LIST @\"useBlockList\"\n\n//use global allow list\n#define PREF_USE_ALLOW_LIST @\"useAllowList\"\n\n//global allow list\n#define PREF_ALLOW_LIST @\"allowList\"\n\n//global block list\n#define PREF_BLOCK_LIST @\"blockList\"\n\n//prefs\n// current profile\n#define PREF_CURRENT_PROFILE @\"currentProfile\"\n\n//install time\n// not really a 'pref' but need to save it\n#define PREF_INSTALL_TIMESTAMP @\"installTime\"\n\n//show alert options\n// not really a 'pref' but need to save it\n#define PREF_ALERT_SHOW_OPTIONS @\"alertShowOptions\"\n\n//rule scope\n// not really a 'pref' but need to save it\n#define PREF_ALERT_LAST_RULE_SCOPE @\"alertLastRuleScope\"\n\n//rule duration\n// not really a 'pref' but need to save it\n#define PREF_ALERT_LAST_RULE_DURATION @\"alertLastRuleDuration\"\n\n//rule duration buttons\n#define RULE_DURATION_BUTTON_ALWAYS 100\n#define RULE_DURATION_BUTTON_PROCESS 101\n#define RULE_DURATION_BUTTON_CUSTOM 102\n\n//rule menu button\n#define RULE_ROW_MENU_BUTTON 110\n\n//log file\n#define LOG_FILE_NAME @\"LuLu.log\"\n\n//error URL\n#define KEY_ERROR_URL @\"errorURL\"\n\n//flag for error popup\n#define KEY_ERROR_SHOULD_EXIT @\"shouldExit\"\n\n//general error URL\n#define FATAL_ERROR_URL @\"https://objective-see.com/errors.html\"\n\n//key for exit code\n#define EXIT_CODE @\"exitCode\"\n\n//key for error msg\n#define KEY_ERROR_MSG @\"errorMsg\"\n\n//key for error sub msg\n#define KEY_ERROR_SUB_MSG @\"errorSubMsg\"\n\n//rules changed\n#define RULES_CHANGED @\"com.objective-see.lulu.rulesChanged\"\n\n//extension event\n#define EXTENSION_EVENT @\"com.objective-see.lulu.extensionEvent\"\n\n/* INSTALLER */\n\n//install directory\n#define INSTALL_DIRECTORY @\"/Library/Objective-See/LuLu\"\n\n//launch daemon name\n#define LAUNCH_DAEMON_BINARY @\"LuLu\"\n\n//launch daemon plist\n#define LAUNCH_DAEMON_PLIST @\"com.objective-see.lulu.plist\"\n\n//installed apps file\n#define INSTALLED_APPS @\"installedApps\"\n\n//frame shift\n// for status msg to avoid activity indicator\n#define FRAME_SHIFT 45\n\n//button title: restart\n#define ACTION_RESTART @\"Restart\"\n\n//flag to reboot\n#define ACTION_RESTART_FLAG -1\n\n//cmdline flag to uninstall\n#define ACTION_UNINSTALL @\"-uninstall\"\n\n//flag to uninstall\n#define ACTION_UNINSTALL_FLAG 0\n\n//cmdline flag to uninstall\n#define ACTION_INSTALL @\"-install\"\n\n//flag to install\n#define ACTION_INSTALL_FLAG 1\n\n//button title: upgrade\n#define ACTION_UPGRADE @\"Upgrade\"\n\n//button title: close\n#define ACTION_CLOSE @\"Close\"\n\n//flag to close\n#define ACTION_CLOSE_FLAG 2\n\n//button title: next\n#define ACTION_NEXT @\"Next »\"\n\n//next\n#define ACTION_NEXT_FLAG 3\n\n//app name\n#define APP_NAME @\"LuLu.app\"\n\n#define CMDLINE_FLAG_WELCOME @\"-welcome\"\n#define CMDLINE_FLAG_PREFS @\"-prefs\"\n#define CMDLINE_FLAG_RULES @\"-rules\"\n\n#define KEY_PATHS @\"paths\"\n#define KEY_RULES @\"rules\"\n\n#define KEY_ID @\"id\"\n#define KEY_PATH @\"path\"\n#define KEY_KEY @\"key\"\n\n#define KEY_CS_ID @\"signatureIdentifier\"\n#define KEY_CS_INFO @\"signingInfo\"\n#define KEY_CS_AUTHS @\"signatureAuthorities\"\n#define KEY_CS_SIGNER @\"signatureSigner\"\n#define KEY_CS_STATUS @\"signatureStatus\"\n#define KEY_CS_ENTITLEMENTS @\"signatureEntitlements\"\n\n#define KEY_TYPE @\"type\"\n\n#define KEY_SCOPE @\"scope\"\n#define KEY_ACTION @\"action\"\n#define KEY_DURATION_PROCESS @\"durationProcess\"\n#define KEY_DURATION_EXPIRATION @\"durationExpiration\"\n\n#define KEY_ENDPOINT_ADDR @\"endpointAddr\"\n#define KEY_ENDPOINT_PORT @\"endpointPort\"\n\n#define KEY_ENDPOINT_ADDR_IS_REGEX @\"endpointAddrIsRegex\"\n\n#define KEY_CS_CHANGE @\"csChange\"\n\n#define KEY_UUID @\"uuid\"\n#define KEY_PROCESS_ID @\"pid\"\n#define KEY_PROCESS_ARGS @\"args\"\n#define KEY_PROCESS_NAME @\"name\"\n#define KEY_PROCESS_PATH @\"path\"\n\n#define KEY_PROCESS_DELETED @\"deleted\"\n\n#define KEY_PROCESS_ANCESTORS @\"ancestors\"\n\n#define KEY_HOST @\"host\"\n#define KEY_URL @\"url\"\n#define KEY_PROTOCOL @\"protocol\"\n#define KEY_ENDPOINT @\"endpoint\"\n\n#define KEY_INDEX @\"index\"\n\n#define KEY_USER_ID @\"userID\"\n\n#define VALUE_ANY @\"*\"\n\n//keys for rule dictionary\n#define RULE_ID @\"id\"\n#define RULE_PATH @\"path\"\n#define RULE_HASH @\"hash\"\n#define RULE_TYPE @\"type\"\n#define RULE_USER @\"user\"\n#define RULE_ACTION @\"action\"\n#define RULE_SIGNING_INFO @\"signingInfo\"\n\n//rules types\n#define RULE_TYPE_ALL     -1\n#define RULE_TYPE_DEFAULT  0\n#define RULE_TYPE_APPLE    1\n#define RULE_TYPE_BASELINE 2\n#define RULE_TYPE_USER     3\n#define RULE_TYPE_PASSIVE  4\n#define RULE_TYPE_RECENT   5\n\n//rule toggle states\n#define RULE_TOGGLE_STATE_ENABLE 1\n#define RULE_TOGGLE_STATE_DISABLE 0\n\n//search (filter) field\n#define RULE_SEARCH_FIELD 5\n\n//network monitor\n#define NETWORK_MONITOR @\"Netiquette.app\"\n\n//scope for action\n// from dropdown in alert window\n#define ACTION_SCOPE_UNSELECTED -1\n#define ACTION_SCOPE_PROCESS 0\n#define ACTION_SCOPE_ENDPOINT 1\n\n//signing info (from ES)\n#define CS_FLAGS @\"csFlags\"\n#define PLATFORM_BINARY @\"platformBinary\"\n#define TEAM_ID @\"teamID\"\n#define SIGNING_ID @\"signingID\"\n\n//rules window\n#define WINDOW_RULES 0\n\n//preferences window\n#define WINDOW_PREFERENCES 1\n\n//key for stdout output\n#define STDOUT @\"stdOutput\"\n\n//key for stderr output\n#define STDERR @\"stdError\"\n\n//key for exit code\n#define EXIT_CODE @\"exitCode\"\n\n/* MAIN APP */\n\n//1st welcome view\n#define WELCOME_VIEW_ONE 1\n\n//2nd welcome view\n#define WELCOME_VIEW_TWO 2\n\n//3rd welcome view\n#define WELCOME_VIEW_THREE 3\n\n//cs consts\n// from: cs_blobs.h\n#define CS_VALID 0x00000001\n#define CS_RUNTIME 0x00010000\n\n//deactivate\n#define ACTION_DEACTIVATE 0\n\n//activate\n#define ACTION_ACTIVATE 1\n\n//rules menu\n#define MENU_RULES_VIEW    1\n#define MENU_RULES_ADD     2\n#define MENU_RULES_IMPORT  3\n#define MENU_RULES_EXPORT  4\n#define MENU_RULES_CLEANUP 5\n\n//os major\n#define SUPPORTED_OS_MAJOR @\"OSMajor\"\n\n//os minor\n#define SUPPORTED_OS_MINOR @\"OSMinor\"\n\n//latest version\n#define LATEST_VERSION @\"version\"\n\n//updates\ntypedef enum {Update_Error, Update_None, Update_NotSupported, Update_Available} UpdateStatus;\n\n//profiles directory\n#define PROFILE_DIRECTORY @\"Profiles\"\n\n#endif /* const_h */\n"
  },
  {
    "path": "LuLu/Shared/signing.h",
    "content": "//\n//  File: Signing.h\n//  Project: Proc Info\n//\n//  Created by: Patrick Wardle\n//  Copyright:  2017 Objective-See\n//\n\n#ifndef Signing_h\n#define Signing_h\n\n@import OSLog;\n@import Foundation;\n\n/* FUNCTIONS */\n\n//get the signing info of a item\n// audit token: extract dynamic code signing info\n// path specified: generate static code signing info\nNSMutableDictionary* extractSigningInfo(audit_token_t* token, NSString* path, SecCSFlags flags);\n\n//determine who signed item\nNSNumber* extractSigner(SecStaticCodeRef code, SecCSFlags flags, BOOL isDynamic);\n\n//validate a requirement\nOSStatus validateRequirement(SecStaticCodeRef code, SecRequirementRef requirement, SecCSFlags flags, BOOL isDynamic);\n\n//extract (names) of signing auths\nNSMutableArray* extractSigningAuths(NSDictionary* signingDetails);\n\n#endif\n"
  },
  {
    "path": "LuLu/Shared/signing.m",
    "content": "//\n//  File: Signing.m\n//  Project: LuLu\n//\n//  Created by: Patrick Wardle\n//  Copyright:  2017 Objective-See\n\n#import \"consts.h\"\n#import \"signing.h\"\n#import \"utilities.h\"\n\n@import Security;\n@import SystemConfiguration;\n\n/* GLOBALS */\n\n//log handle\nextern os_log_t logHandle;\n\n//get the signing info of a item\n// audit token: extract dynamic code signing info\n// path on disk: generate static code signing info\nNSMutableDictionary* extractSigningInfo(audit_token_t* token, NSString* path, SecCSFlags flags)\n{\n    //info dictionary\n    NSMutableDictionary* signingInfo = nil;\n    \n    //status\n    OSStatus status = !errSecSuccess;\n    \n    //static code ref\n    SecStaticCodeRef staticCode = NULL;\n    \n    //dynamic code ref\n    SecCodeRef dynamicCode = NULL;\n    \n    //signing details\n    CFDictionaryRef signingDetails = NULL;\n    \n    //signing authorities\n    NSMutableArray* signingAuths = nil;\n    \n    //init signing status\n    signingInfo = [NSMutableDictionary dictionary];\n    \n    //dynamic code checks\n    // no path, dynamic check via pid\n    if(nil == path)\n    {\n        //obtain dynamic code ref from (audit) token\n        status = SecCodeCopyGuestWithAttributes(NULL, (__bridge CFDictionaryRef _Nullable)(@{(__bridge NSString *)kSecGuestAttributeAudit:[NSData dataWithBytes:token length:sizeof(audit_token_t)]}), kSecCSDefaultFlags, &dynamicCode);\n        if(errSecSuccess != status)\n        {\n            //err msg\n            os_log_error(logHandle, \"ERROR: 'SecCodeCopyGuestWithAttributes' failed with %d/%#x\", status, status);\n            \n            //set error\n            signingInfo[KEY_CS_STATUS] = [NSNumber numberWithInt:status];\n            \n            //bail\n            goto bail;\n        }\n        \n        //validate code\n        status = SecCodeCheckValidity(dynamicCode, flags, NULL);\n        if(errSecSuccess != status)\n        {\n            //err msg\n            os_log_error(logHandle, \"ERROR: 'SecCodeCheckValidity' failed with %d/%#x\", status, status);\n            \n            //set error\n            signingInfo[KEY_CS_STATUS] = [NSNumber numberWithInt:status];\n            \n            //bail\n            goto bail;\n        }\n        \n        //happily signed\n        signingInfo[KEY_CS_STATUS] = [NSNumber numberWithInt:errSecSuccess];\n        \n        //determine signer\n        // apple, app store, dev id, adhoc, etc...\n        signingInfo[KEY_CS_SIGNER] = extractSigner(dynamicCode, flags, YES);\n        \n        //extract signing info\n        status = SecCodeCopySigningInformation(dynamicCode, kSecCSSigningInformation, &signingDetails);\n        if(errSecSuccess != status)\n        {\n            //err msg\n            os_log_error(logHandle, \"ERROR: 'SecCodeCopySigningInformation' failed with %d/%#x\", status, status);\n            \n            //set error\n            signingInfo[KEY_CS_STATUS] = [NSNumber numberWithInt:status];\n            \n            //bail\n            goto bail;\n        }\n    }\n    \n    //static code checks\n    else\n    {\n        //create static code ref via path\n        status = SecStaticCodeCreateWithPath((__bridge CFURLRef)([NSURL fileURLWithPath:path]), kSecCSDefaultFlags, &staticCode);\n        if(errSecSuccess != status)\n        {\n            //err msg\n            os_log_error(logHandle, \"ERROR: 'SecStaticCodeCreateWithPath' failed with %d/%#x\", status, status);\n            \n            //set error\n            signingInfo[KEY_CS_STATUS] = [NSNumber numberWithInt:status];\n            \n            //bail\n            goto bail;\n        }\n        \n        //check signature\n        status = SecStaticCodeCheckValidity(staticCode, flags, NULL);\n        if(errSecSuccess != status)\n        {\n            //err msg\n            os_log_error(logHandle, \"'SecStaticCodeCheckValidity' failed with %d/%#x\", status, status);\n            \n            //set error\n            signingInfo[KEY_CS_STATUS] = [NSNumber numberWithInt:status];\n            \n            //bail\n            goto bail;\n        }\n        \n        //happily signed\n        signingInfo[KEY_CS_STATUS] = [NSNumber numberWithInt:errSecSuccess];\n        \n        //determine signer\n        // apple, app store, dev id, adhoc, etc...\n        signingInfo[KEY_CS_SIGNER] = extractSigner(staticCode, flags, NO);\n        \n        //extract signing info\n        status = SecCodeCopySigningInformation(staticCode, kSecCSSigningInformation, &signingDetails);\n        if(errSecSuccess != status)\n        {\n            //err msg\n            os_log_error(logHandle, \"'SecCodeCopySigningInformation' failed with %d/%#x\", status, status);\n            \n            //set error\n            signingInfo[KEY_CS_STATUS] = [NSNumber numberWithInt:status];\n            \n            //bail\n            goto bail;\n        }\n    }\n    \n    //extract code signing id\n    if(0 != [[(__bridge NSDictionary*)signingDetails objectForKey:(__bridge NSString*)kSecCodeInfoIdentifier] length])\n    {\n        //extract/save\n        signingInfo[KEY_CS_ID] = [(__bridge NSDictionary*)signingDetails objectForKey:(__bridge NSString*)kSecCodeInfoIdentifier];\n    }\n    \n    //extract signing authorities\n    signingAuths = extractSigningAuths((__bridge NSDictionary *)(signingDetails));\n    if(0 != signingAuths.count)\n    {\n        //save\n        signingInfo[KEY_CS_AUTHS] = signingAuths;\n    }\n    \nbail:\n    \n    //free signing info\n    if(NULL != signingDetails)\n    {\n        //free\n        CFRelease(signingDetails);\n        signingDetails = NULL;\n    }\n    \n    //free dynamic code\n    if(NULL != dynamicCode)\n    {\n        //free\n        CFRelease(dynamicCode);\n        dynamicCode = NULL;\n    }\n    \n    //free static code\n    if(NULL != staticCode)\n    {\n        //free\n        CFRelease(staticCode);\n        staticCode = NULL;\n    }\n    \n    return signingInfo;\n}\n\n//determine who signed item\nNSNumber* extractSigner(SecStaticCodeRef code, SecCSFlags flags, BOOL isDynamic)\n{\n    //result\n    NSNumber* signer = nil;\n    \n    //\"anchor apple\"\n    static SecRequirementRef isApple = nil;\n    \n    //\"anchor apple generic\"\n    static SecRequirementRef isDevID = nil;\n    \n    //\"Apple Mac OS Application Signing\"\n    static SecRequirementRef isAppStore = nil;\n    \n    //\"Apple iPhone OS Application Signing\"\n    static SecRequirementRef isiOSAppStore = nil;\n    \n    //Apple's app store team ids\n    static NSSet* appleTeamIDs = nil;\n    \n    //signing details\n    CFDictionaryRef signingDetails = NULL;\n    \n    //team id\n    NSString* teamID = nil;\n    \n    //token\n    static dispatch_once_t onceToken = 0;\n    \n    //only once\n    // init requirements\n    dispatch_once(&onceToken, ^{\n        \n        //init apple signing requirement\n        SecRequirementCreateWithString(CFSTR(\"anchor apple\"), kSecCSDefaultFlags, &isApple);\n        \n        //init dev id signing requirement\n        SecRequirementCreateWithString(CFSTR(\"anchor apple generic\"), kSecCSDefaultFlags, &isDevID);\n        \n        //init (macOS)  app store signing requirement\n        SecRequirementCreateWithString(CFSTR(\"anchor apple generic and certificate leaf [subject.CN] = \\\"Apple Mac OS Application Signing\\\"\"), kSecCSDefaultFlags, &isAppStore);\n        \n        //init (iOS) app store signing requirement\n        SecRequirementCreateWithString(CFSTR(\"anchor apple generic and certificate leaf [subject.CN] = \\\"Apple iPhone OS Application Signing\\\"\"), kSecCSDefaultFlags, &isiOSAppStore);\n        \n        //init Apple's App Store team IDs\n        appleTeamIDs = [NSSet setWithArray:@[@\"K36BKF7T3D\", @\"74J34U3R6X\", @\"59GAB85EFG\", @\"APPLECOMPUTER\"]];\n    });\n    \n    //check 1: \"is apple\" (proper)\n    if(errSecSuccess == validateRequirement(code, isApple, flags, isDynamic))\n    {\n        //set signer to apple\n        signer = [NSNumber numberWithInt:Apple];\n    }\n\n    //check 2: \"is app store\"\n    // note: this is more specific than dev id, so do it first\n    else if(errSecSuccess == validateRequirement(code, isAppStore, flags, isDynamic))\n    {\n        //default signer to app store\n        signer = [NSNumber numberWithInt:AppStore];\n        \n        //however, set back to apple\n        // ...if it's one of apple's app store apps\n        if(errSecSuccess == SecCodeCopySigningInformation(code, kSecCSSigningInformation, &signingDetails))\n        {\n            //extract team id\n            // and check if it belongs to apple\n            teamID = [(__bridge NSDictionary*)signingDetails objectForKey:(__bridge NSString*)kSecCodeInfoTeamIdentifier];\n            if( (nil != teamID) &&\n                (YES == [appleTeamIDs containsObject:teamID]))\n            {\n               //set signer to apple\n               signer = [NSNumber numberWithInt:Apple];\n            }\n            \n            //release\n            CFRelease(signingDetails);\n            signingDetails = NULL;\n        }\n    }\n    \n    //check 3: \"is (iOS) app store\"\n    // note: this is more specific than dev id, so also do it first\n    else if(errSecSuccess == validateRequirement(code, isiOSAppStore, flags, isDynamic))\n    {\n        //set signer to app store\n        signer = [NSNumber numberWithInt:AppStore];\n    }\n    \n    //check 4: \"is dev id\"\n    else if(errSecSuccess == validateRequirement(code, isDevID, flags, isDynamic))\n    {\n        //set signer to dev id\n        signer = [NSNumber numberWithInt:DevID];\n    }\n    \n    //otherwise\n    // has to be adhoc?\n    else\n    {\n        //set signer to ad hoc\n        signer = [NSNumber numberWithInt:AdHoc];\n    }\n    \n    return signer;\n}\n\n//validate a requirement\nOSStatus validateRequirement(SecStaticCodeRef code, SecRequirementRef requirement, SecCSFlags flags, BOOL isDynamic)\n{\n    //result\n    OSStatus result = -1;\n    \n    //dynamic check?\n    if(YES == isDynamic)\n    {\n        //validate dynamically\n        result = SecCodeCheckValidity((SecCodeRef)code, flags, requirement);\n    }\n    //static check\n    else\n    {\n        //validate statically\n        result = SecStaticCodeCheckValidity(code, flags, requirement);\n    }\n    \n    return result;\n}\n\n//extract (names) of signing auths\nNSMutableArray* extractSigningAuths(NSDictionary* signingDetails)\n{\n    //signing auths\n    NSMutableArray* authorities = nil;\n    \n    //cert chain\n    NSArray* certificateChain = nil;\n    \n    //index\n    NSUInteger index = 0;\n    \n    //cert\n    SecCertificateRef certificate = NULL;\n    \n    //common name on chert\n    CFStringRef commonName = NULL;\n    \n    //init array for certificate names\n    authorities = [NSMutableArray array];\n    \n    //get cert chain\n    certificateChain = [signingDetails objectForKey:(__bridge NSString*)kSecCodeInfoCertificates];\n    if(0 == certificateChain.count)\n    {\n        //no certs\n        goto bail;\n    }\n    \n    //extract/save name of all certs\n    for(index = 0; index < certificateChain.count; index++)\n    {\n        //reset\n        commonName = NULL;\n        \n        //extract cert\n        certificate = (__bridge SecCertificateRef)([certificateChain objectAtIndex:index]);\n        \n        //get common name\n        if( (errSecSuccess == SecCertificateCopyCommonName(certificate, &commonName)) &&\n            (NULL != commonName) )\n        {\n            //save\n            [authorities addObject:(__bridge NSString*)(commonName)];\n            \n            //release\n            CFRelease(commonName);\n        }\n    }\n        \nbail:\n    \n    return authorities;\n}\n"
  },
  {
    "path": "LuLu/Shared/utilities.h",
    "content": "//\n//  file: utilities.h\n//  project: lulu (shared)\n//  description: various helper/utility functions (header)\n//\n//  created by Patrick Wardle\n//  copyright (c) 2017 Objective-See. All rights reserved.\n//\n\n#ifndef Utilities_h\n#define Utilities_h\n\n@import AppKit;\n@import Foundation;\n\n/* FUNCTIONS */\n\n//give path to bundle\n// get full path to its binary\nNSString* getBundleExecutable(NSString* appPath);\n\n//get app's version\n// extracted from Info.plist\nNSString* getAppVersion(void);\n\n//get (true) parent\nNSDictionary* getRealParent(pid_t pid);\n\n//get name of logged in user\nNSString* getConsoleUser(void);\n\n//given a path to binary\n// parse it back up to find app's bundle\nNSBundle* findAppBundle(NSString* binaryPath);\n\n//get process's path\nNSString* getProcessPath(pid_t pid);\n\n//get process name\n// either via app bundle, or path\nNSString* getProcessName(pid_t pid, NSString* path);\n\n//get current working dir\nNSString* getProcessCWD(pid_t pid);\n\n//given a process path and user\n// return array of all matching pids\nNSMutableArray* getProcessIDs(NSString* processPath, int userID);\n\n//get parent pid\npid_t getParent(int pid);\n\n//enable/disable a menu\nvoid toggleMenu(NSMenu* menu, BOOL shouldEnable);\n\n//toggle login item\n// either add (install) or remove (uninstall)\nBOOL toggleLoginItem(NSURL* loginItem, int toggleFlag);\n\n//get an icon for a process\n// for apps, this will be app's icon, otherwise just a standard system one\nNSImage* getIconForProcess(NSString* path);\n\n//wait until a window is non nil\n// then make it modal\nvoid makeModal(NSWindowController* windowController);\n\n//find all processes by name\nNSMutableArray* findProcesses(NSString* processName);\n\n//hash a file (sha256)\nNSMutableString* hashFile(NSString* filePath);\n\n//loads a framework\n// note: assumes is in 'Framework' dir\nNSBundle* loadFramework(NSString* name);\n\n//check if (full) dark mode\n// meaning, Mojave+ and dark mode enabled\nBOOL isDarkMode(void);\n\n//check if something is nil\n// if so, return a default ('unknown') value\nNSString* valueForStringItem(NSString* item);\n\n//grab date added\n// extracted via 'kMDItemDateAdded'\nNSDate* dateAdded(NSString* file);\n\n//show an alert\nNSModalResponse showAlert(NSAlertStyle style, NSString* messageText, NSString* informativeText, NSArray* buttons);\n\n//get audit token for pid\nNSData* tokenForPid(pid_t pid);\n\n//given an ip address\n// reverse resolves it\nNSArray* resolveAddress(NSString * address);\n\n//process alive?\nBOOL isAlive(pid_t processID);\n\n//check if app is an simulator app\n// for now check 'iPhoneSimulator' and 'AppleTVSimulator'\nBOOL isSimulatorApp(NSString* path);\n\n//was app launched by user\nBOOL launchedByUser(void);\n\n//fade out a window\nvoid fadeOut(NSWindow* window, float duration);\n\n//matches CS info?\nBOOL matchesCSInfo(NSDictionary* csInfo_1, NSDictionary* csInfo_2);\n\n//escape string\nNSString* toEscapedJSON(NSString* input);\n\n//convert date to absolute\nNSDate* absoluteDate(NSDate* date);\n\n//generate list of ancestors\nNSMutableArray* generateProcessHierarchy(pid_t child);\n\n//is process on internal drive?\nBOOL isInternalProcess(NSString *path);\n\n#endif\n"
  },
  {
    "path": "LuLu/Shared/utilities.m",
    "content": "//\n//  file: utilities.m\n//  project: lulu (shared)\n//  description: various helper/utility functions\n//\n//  created by Patrick Wardle\n//  copyright (c) 2017 Objective-See. All rights reserved.\n//\n\n#import \"consts.h\"\n#import \"utilities.h\"\n#import \"AppDelegate.h\"\n\n@import OSLog;\n@import Carbon;\n@import Security;\n@import Foundation;\n@import CommonCrypto;\n@import SystemConfiguration;\n\n#import <netdb.h>\n#import <dlfcn.h>\n#import <signal.h>\n#import <unistd.h>\n#import <libproc.h>\n#import <sys/stat.h>\n#import <arpa/inet.h>\n#import <sys/socket.h>\n#import <sys/sysctl.h>\n\n/* GLOBALS */\n\n//log handle\nextern os_log_t logHandle;\n\n//get app's version\n// extracted from Info.plist\nNSString* getAppVersion(void)\n{\n    //read and return 'CFBundleVersion' from bundle\n    return [[[NSBundle mainBundle] infoDictionary] objectForKey:@\"CFBundleVersion\"];\n}\n\n//give path to bundle\n// get full path to its binary\nNSString* getBundleExecutable(NSString* appPath)\n{\n    //binary path\n    NSString* binaryPath = nil;\n    \n    //app bundle\n    NSBundle* appBundle = nil;\n    \n    //load app bundle\n    appBundle = [NSBundle bundleWithPath:appPath];\n    if(nil == appBundle)\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: failed to load app bundle for %{public}@\", appPath);\n        \n        //bail\n        goto bail;\n    }\n    \n    //extract executable\n    binaryPath = [appBundle.executablePath stringByResolvingSymlinksInPath];\n    \nbail:\n    \n    return binaryPath;\n}\n\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wdeprecated-declarations\"\n\n//get (true) parent\nNSDictionary* getRealParent(pid_t pid)\n{\n    //process info\n    NSDictionary* processInfo = nil;\n    \n    //process serial number\n    ProcessSerialNumber psn = {0, kNoProcess};\n    \n    //(parent) process serial number\n    ProcessSerialNumber ppsn = {0, kNoProcess};\n    \n    //get process serial number from pid\n    if(noErr != GetProcessForPID(pid, &psn))\n    {\n        //err\n        goto bail;\n    }\n    \n    //get process (carbon) info\n    processInfo = CFBridgingRelease(ProcessInformationCopyDictionary(&psn, (UInt32)kProcessDictionaryIncludeAllInformationMask));\n    if(nil == processInfo)\n    {\n        //err\n        goto bail;\n    }\n    \n    //extract/convert parent ppsn\n    ppsn.lowLongOfPSN =  [processInfo[@\"ParentPSN\"] longLongValue] & 0x00000000FFFFFFFFLL;\n    ppsn.highLongOfPSN = ([processInfo[@\"ParentPSN\"] longLongValue] >> 32) & 0x00000000FFFFFFFFLL;\n    \n    //get parent process (carbon) info\n    processInfo = CFBridgingRelease(ProcessInformationCopyDictionary(&ppsn, (UInt32)kProcessDictionaryIncludeAllInformationMask));\n    if(nil == processInfo)\n    {\n        //err\n        goto bail;\n    }\n    \nbail:\n    \n    return processInfo;\n}\n\n#pragma GCC diagnostic pop\n\n//generate list of ancestors\nNSMutableArray* generateProcessHierarchy(pid_t child)\n{\n    //ancestors\n    NSMutableArray* ancestors = nil;\n    \n    //current process id\n    pid_t currentPID = -1;\n    \n    //current path\n    NSString* currentPath = nil;\n    \n    //current name\n    NSString* currentName = nil;\n    \n    //parent pid\n    pid_t parentPID = -1;\n    \n    //rpid function\n    static pid_t (*getRPID)(pid_t pid) = NULL;\n    \n    //token\n    static dispatch_once_t onceToken = 0;\n    \n    //init\n    ancestors = [NSMutableArray array];\n    \n    //only once\n    // init requirements\n    dispatch_once(&onceToken, ^{\n        \n        //get function pointer\n        getRPID = dlsym(RTLD_NEXT, \"responsibility_get_pid_responsible_for_pid\");\n        \n    });\n    \n    //start w/ self\n    currentPID = child;\n    \n    do {\n        \n        //get path\n        if(nil == (currentPath = getProcessPath(currentPID)))\n        {\n            //default\n            currentPath = NSLocalizedString(@\"unknown\", @\"unknown\");\n        }\n        \n        //get name\n        currentName = getProcessName(0, currentPath);\n        if(nil == currentName)\n        {\n            //default\n            currentName = NSLocalizedString(@\"unknown\", @\"unknown\");\n        }\n        \n        //add\n        [ancestors insertObject:[@{KEY_PROCESS_ID:[NSNumber numberWithInt:currentPID], KEY_PROCESS_PATH:currentPath, KEY_PROCESS_NAME:currentName} mutableCopy] atIndex:0];\n        \n        //for apps (and if we're not root)\n        // try application services pid via serial\n        if(0 != getuid())\n        {\n            //real parent via serial\n            parentPID = [getRealParent(currentPID)[@\"pid\"] intValue];\n        }\n        \n        //not found\n        // try via responsible pid\n        if(0 == parentPID)\n        {\n            //for parent\n            // first try via rPID\n            if(NULL != getRPID)\n            {\n                //get rpid\n                parentPID = getRPID(currentPID);\n            }\n        }\n        \n        //couldn't find/get rPID?\n        // default back to using standard method\n        if( (parentPID <= 0) ||\n            (currentPID == parentPID) )\n        {\n            //get parent pid\n            parentPID = getParent(currentPID);\n        }\n        \n        //done?\n        if( (parentPID <= 0) ||\n            (currentPID == parentPID) )\n        {\n            //bail\n            break;\n        }\n        \n        //update\n        currentPID = parentPID;\n        \n    } while(YES);\n    \n    //now, will all items added\n    // add each item's index for UI purposes\n    for(NSUInteger i = 0; i < ancestors.count; i++)\n    {\n        //set index\n        ancestors[i][KEY_INDEX] = [NSNumber numberWithInteger:i];\n    }\n\n    return ancestors;\n}\n\n//get name of logged in user\nNSString* getConsoleUser(void)\n{\n    //copy/return user\n    return CFBridgingRelease(SCDynamicStoreCopyConsoleUser(NULL, NULL, NULL));\n}\n\n//get process name\n// either via app bundle, or path\nNSString* getProcessName(pid_t pid, NSString* path)\n{\n    //status\n    int status = -1;\n    \n    //process name\n    NSString* processName = nil;\n    \n    //app bundle\n    NSBundle* appBundle = nil;\n    \n    //buffer for process path\n    char nameBuffer[PROC_PIDPATHINFO_MAXSIZE] = {0};\n    \n    //clear\n    memset(nameBuffer, 0x0, sizeof(nameBuffer));\n    \n    //via pid?\n    if(pid != 0)\n    {\n        //get name\n        status = proc_name(pid, &nameBuffer, sizeof(nameBuffer));\n        if(status >= 0)\n        {\n            //init task's name\n            processName = [NSString stringWithUTF8String:nameBuffer];\n        }\n    }\n    \n    //(still) nil\n    // try via app bundle\n    if(nil == processName)\n    {\n        //find app bundle\n        appBundle = findAppBundle(path);\n        if(nil != appBundle)\n        {\n            //grab name from app's bundle\n            processName = [appBundle infoDictionary][@\"CFBundleName\"];\n        }\n    }\n    \n    //(still) nil\n    // just grab from path\n    if(nil == processName)\n    {\n        //from path\n        processName = [path lastPathComponent];\n    }\n    \n    return processName;\n}\n\n//given a path to binary\n// parse it back up to find app's bundle\nNSBundle* findAppBundle(NSString* path)\n{\n    //app's bundle\n    NSBundle* appBundle = nil;\n    \n    //standarized path\n    NSString* standardedPath = nil;\n    \n    //app's path\n    NSString* appPath = nil;\n    \n    //standardize path\n    standardedPath = [[path stringByStandardizingPath] stringByResolvingSymlinksInPath];\n    \n    //first just try full path\n    appPath = standardedPath;\n    \n    //try to find the app's bundle\n    do\n    {\n        //try to load app's bundle\n        appBundle = [NSBundle bundleWithPath:appPath];\n        \n        //was an app passed in?\n        if(YES == [appBundle.bundlePath isEqualToString:standardedPath])\n        {\n            //all done\n            break;\n        }\n        \n        //check for match\n        // binary path's match\n        if( (nil != appBundle) &&\n            (YES == [appBundle.executablePath isEqualToString:standardedPath]))\n        {\n            //all done\n            break;\n        }\n        \n        //unset\n        appBundle = nil;\n        \n        //remove last part\n        // will try this next\n        appPath = [appPath stringByDeletingLastPathComponent];\n        \n    //scan until we get to root\n    // of course, loop will exit if app info dictionary is found/loaded\n    } while( (nil != appPath) &&\n             (YES != [appPath isEqualToString:@\"/\"]) &&\n             (YES != [appPath isEqualToString:@\"\"]) );\n    \n    return appBundle;\n}\n\n//get process's path\nNSString* getProcessPath(pid_t pid)\n{\n    //task path\n    NSString* processPath = nil;\n    \n    //cwd\n    NSString* cwd = nil;\n    \n    //buffer for process path\n    char pathBuffer[PROC_PIDPATHINFO_MAXSIZE] = {0};\n    \n    //status\n    int status = -1;\n    \n    //'management info base' array\n    int mib[3] = {0};\n    \n    //system's size for max args\n    unsigned long systemMaxArgs = 0;\n    \n    //process's args\n    char* taskArgs = NULL;\n    \n    //# of args\n    int numberOfArgs = 0;\n    \n    //size of buffers, etc\n    size_t size = 0;\n    \n    //reset buffer\n    memset(pathBuffer, 0x0, PROC_PIDPATHINFO_MAXSIZE);\n    \n    //first attempt to get path via 'proc_pidpath()'\n    status = proc_pidpath(pid, pathBuffer, sizeof(pathBuffer));\n    if(0 != status)\n    {\n        //init task's name\n        processPath = [NSString stringWithUTF8String:pathBuffer];\n    }\n    //otherwise\n    // try via task's args ('KERN_PROCARGS2')\n    else\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: for process %d, 'proc_pidpath' failed with %d (errno: %d)\", pid, status, errno);\n        \n        //init mib\n        // want system's size for max args\n        mib[0] = CTL_KERN;\n        mib[1] = KERN_ARGMAX;\n        \n        //set size\n        size = sizeof(systemMaxArgs);\n        \n        //get system's size for max args\n        if(-1 == sysctl(mib, 2, &systemMaxArgs, &size, NULL, 0))\n        {\n            //bail\n            goto bail;\n        }\n        \n        //alloc space for args\n        taskArgs = malloc(systemMaxArgs);\n        if(NULL == taskArgs)\n        {\n            //bail\n            goto bail;\n        }\n        \n        //init mib\n        // want process args\n        mib[0] = CTL_KERN;\n        mib[1] = KERN_PROCARGS2;\n        mib[2] = pid;\n        \n        //set size\n        size = (size_t)systemMaxArgs;\n        \n        //get process's args\n        if(-1 == sysctl(mib, 3, taskArgs, &size, NULL, 0))\n        {\n            //bail\n            goto bail;\n        }\n        \n        //sanity check\n        // ensure buffer is somewhat sane\n        if(size <= sizeof(int))\n        {\n            //bail\n            goto bail;\n        }\n        \n        //extract number of args\n        memcpy(&numberOfArgs, taskArgs, sizeof(numberOfArgs));\n        \n        //extract task's name\n        // follows # of args (int) and is NULL-terminated\n        processPath = [NSString stringWithUTF8String:taskArgs + sizeof(int)];\n        \n        //short path?\n        // get cwd + to append\n        if(YES == [processPath hasPrefix:@\"./\"])\n        {\n            //chop ./\n            processPath = [processPath substringWithRange:NSMakeRange(2, [processPath length]-2)];\n            cwd = getProcessCWD(pid);\n            if(nil != cwd)\n            {\n                //append\n                processPath = [cwd stringByAppendingPathComponent:processPath];\n            }\n        }\n    }\n    \nbail:\n    \n    //free process args\n    if(NULL != taskArgs)\n    {\n        //free\n        free(taskArgs);\n        taskArgs = NULL;\n    }\n    \n    return processPath;\n}\n\n//get current working dir\nNSString* getProcessCWD(pid_t pid)\n{\n    //cwd\n    NSString* directory = nil;\n    \n    //status\n    int status = -1;\n    \n    //path info\n    struct proc_vnodepathinfo vpi = {0,};\n    \n    //init\n    memset(&vpi, 0x0, sizeof(vpi));\n    \n    //get proc's cwd, via PROC_PIDVNODEPATHINFO\n    status = proc_pidinfo(pid, PROC_PIDVNODEPATHINFO, 0, &vpi, sizeof(vpi));\n    if(status > 0)\n    {\n        //convert to string\n        directory = [NSString stringWithUTF8String:vpi.pvi_cdir.vip_path];\n    }\n    \n    return directory;\n}\n\n//given a process path and user\n// return array of all matching pids\nNSMutableArray* getProcessIDs(NSString* processPath, int userID)\n{\n    //status\n    int status = -1;\n    \n    //process IDs\n    NSMutableArray* processIDs = nil;\n    \n    //# of procs\n    int numberOfProcesses = 0;\n        \n    //array of pids\n    pid_t* pids = NULL;\n    \n    //process info struct\n    struct kinfo_proc procInfo = {0};\n    \n    //size of struct\n    size_t procInfoSize = sizeof(procInfo);\n    \n    //mib\n    int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, -1};\n    \n    //clear buffer\n    memset(&procInfo, 0x0, procInfoSize);\n    \n    //get # of procs\n    numberOfProcesses = proc_listallpids(NULL, 0);\n    if(-1 == numberOfProcesses)\n    {\n        //bail\n        goto bail;\n    }\n    \n    //alloc buffer for pids\n    pids = calloc((unsigned long)numberOfProcesses, sizeof(pid_t));\n    \n    //alloc\n    processIDs = [NSMutableArray array];\n    \n    //get list of pids\n    status = proc_listallpids(pids, numberOfProcesses * (int)sizeof(pid_t));\n    if(status < 0)\n    {\n        //bail\n        goto bail;\n    }\n        \n    //iterate over all pids\n    // get name for each process\n    for(int i = 0; i < (int)numberOfProcesses; i++)\n    {\n        //skip blank pids\n        if(0 == pids[i])\n        {\n            //skip\n            continue;\n        }\n        \n        //skip if path doesn't match\n        if(YES != [processPath isEqualToString:getProcessPath(pids[i])])\n        {\n            //next\n            continue;\n        }\n        \n        //need to also match on user?\n        // caller can pass in -1 to skip this check\n        if(-1 != userID)\n        {\n            //init mib\n            mib[0x3] = pids[i];\n            \n            //make syscall to get proc info for user\n            if( (0 != sysctl(mib, 0x4, &procInfo, &procInfoSize, NULL, 0)) ||\n                (0 == procInfoSize) )\n            {\n                //skip\n                continue;\n            }\n\n            //skip if user id doesn't match\n            if(userID != (int)procInfo.kp_eproc.e_ucred.cr_uid)\n            {\n                //skip\n                continue;\n            }\n        }\n        \n        //got match\n        // add to list\n        [processIDs addObject:[NSNumber numberWithInt:pids[i]]];\n    }\n    \nbail:\n        \n    //free buffer\n    if(NULL != pids)\n    {\n        //free\n        free(pids);\n        \n        //reset\n        pids = NULL;\n    }\n    \n    return processIDs;\n}\n\n//enable/disable a menu\nvoid toggleMenu(NSMenu* menu, BOOL shouldEnable)\n{\n    //disable autoenable\n    menu.autoenablesItems = NO;\n    \n    //iterate over\n    // set state of each item\n    for(NSMenuItem* item in menu.itemArray)\n    {\n        //set state\n        item.enabled = shouldEnable;\n    }\n    \n    return;\n}\n\n//get an icon for a process\n// for apps (and their helpers), this will be app's icon, otherwise just a standard system one\nNSImage* getIconForProcess(NSString* item)\n{\n    //icon's file name\n    NSString* iconFile = nil;\n    \n    //icon's path\n    NSString* iconPath = nil;\n    \n    //icon's path extension\n    NSString* iconExtension = nil;\n    \n    //icon\n    NSImage* icon = nil;\n    \n    //system's document icon\n    static NSImage* documentIcon = nil;\n    \n    //bundle\n    NSBundle* appBundle = nil;\n    \n    //path\n    // might change if we find a parent\n    NSString* path = item;\n    \n    //invalid path?\n    // grab a default icon and bail\n    if(YES != [NSFileManager.defaultManager fileExistsAtPath:path])\n    {\n        //set icon to system 'application' icon\n        icon = [[NSWorkspace sharedWorkspace]\n                iconForFileType: NSFileTypeForHFSTypeCode(kGenericApplicationIcon)];\n        \n        //set size to 64 @2x\n        [icon setSize:NSMakeSize(128, 128)];\n   \n        //bail\n        goto bail;\n    }\n    \n    //helper?\n    if( [path containsString:@\"Helper\"] &&\n        [path.pathExtension isEqualToString:@\"app\"])\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"%{public}@ appears to be a helper app\", path);\n        \n        NSBundle* bundle = [NSBundle bundleWithPath:path];\n        NSString* iconFile = [bundle objectForInfoDictionaryKey:@\"CFBundleIconFile\"];\n        NSString* iconName = [bundle objectForInfoDictionaryKey:@\"CFBundleIconName\"];\n        \n        //no icon? find parent\n        if(!(iconFile.length || iconName.length))\n        {\n            NSString *currentPath = path;\n            \n            //find parent\n            while(currentPath.length > 1) {\n                \n                currentPath = [currentPath stringByDeletingLastPathComponent];\n                \n                if([currentPath.pathExtension isEqualToString:@\"app\"] && ![currentPath containsString:@\"Helper\"]) {\n                    \n                    //update\n                    path = currentPath;\n                    \n                    //dbg msg\n                    os_log_debug(logHandle, \"will use parents path for icon: %{public}@\", path);\n                    \n                    break;\n                }\n            }\n        }\n    }\n    \n    //first try grab bundle\n    // then extact icon from this\n    appBundle = findAppBundle(path);\n    if(nil != appBundle)\n    {\n        //extract icon\n        icon = [NSWorkspace.sharedWorkspace iconForFile:appBundle.bundlePath];\n        if(nil != icon)\n        {\n            //done!\n            goto bail;\n        }\n        \n        //get file\n        iconFile = appBundle.infoDictionary[@\"CFBundleIconFile\"];\n        \n        //get path extension\n        iconExtension = [iconFile pathExtension];\n        \n        //if its blank (i.e. not specified)\n        // go with 'icns'\n        if(YES == [iconExtension isEqualTo:@\"\"])\n        {\n            //set type\n            iconExtension = @\"icns\";\n        }\n        \n        //set full path\n        iconPath = [appBundle pathForResource:[iconFile stringByDeletingPathExtension] ofType:iconExtension];\n        \n        //load it\n        icon = [[NSImage alloc] initWithContentsOfFile:iconPath];\n    }\n    \n    //process is not an app or couldn't get icon\n    // try to get it via shared workspace\n    if( (nil == appBundle) ||\n        (nil == icon) )\n    {\n        //extract icon\n        icon = [[NSWorkspace sharedWorkspace] iconForFile:path];\n        \n        //load system document icon\n        // static var, so only load once\n        if(nil == documentIcon)\n        {\n            //load\n            documentIcon = [[NSWorkspace sharedWorkspace] iconForFileType:\n                            NSFileTypeForHFSTypeCode(kGenericDocumentIcon)];\n        }\n        \n        //if 'iconForFile' method doesn't find and icon, it returns the system 'document' icon\n        // the system 'application' icon seems more applicable, so use that here...\n        if(YES == [icon isEqual:documentIcon])\n        {\n            //set icon to system 'application' icon\n            icon = [[NSWorkspace sharedWorkspace]\n                    iconForFileType: NSFileTypeForHFSTypeCode(kGenericApplicationIcon)];\n        }\n        \n        //'iconForFileType' returns small icons\n        // so set size to 64 @2x\n        [icon setSize:NSMakeSize(128, 128)];\n    }\n    \nbail:\n    \n    return icon;\n}\n\n//wait till window non-nil\n// then make that window modal\nvoid makeModal(NSWindowController* windowController)\n{\n    //window\n    __block NSWindow* window = nil;\n    \n    //wait till non-nil\n    // then make window modal\n    for(int i=0; i<20; i++)\n    {\n        //grab window\n        dispatch_sync(dispatch_get_main_queue(), ^{\n         \n            //grab\n            window = windowController.window;\n            \n        });\n                      \n        //nil?\n        // nap\n        if(nil == window)\n        {\n            //nap\n            [NSThread sleepForTimeInterval:0.05f];\n            \n            //next\n            continue;\n        }\n        \n        //have window?\n        // make it modal\n        dispatch_sync(dispatch_get_main_queue(), ^{\n            \n            //modal\n            [[NSApplication sharedApplication] runModalForWindow:windowController.window];\n            \n        });\n        \n        //done\n        break;\n    }\n    \n    return;\n}\n\n//find all processes by name\nNSMutableArray* findProcesses(NSString* processName)\n{\n    //status\n    int status = -1;\n    \n    //pids\n    NSMutableArray* processes = nil;\n    \n    //# of procs\n    int numberOfProcesses = 0;\n    \n    //array of pids\n    pid_t* pids = NULL;\n    \n    //process path\n    NSString* processPath = nil;\n    \n    //init\n    processes = [NSMutableArray array];\n    \n    //get # of procs\n    numberOfProcesses = proc_listpids(PROC_ALL_PIDS, 0, NULL, 0);\n    if(-1 == numberOfProcesses)\n    {\n        //bail\n        goto bail;\n    }\n    \n    //alloc buffer for pids\n    pids = calloc((unsigned long)numberOfProcesses, sizeof(pid_t));\n    \n    //get list of pids\n    status = proc_listpids(PROC_ALL_PIDS, 0, pids, numberOfProcesses * (int)sizeof(pid_t));\n    if(status < 0)\n    {\n        //bail\n        goto bail;\n    }\n    \n    //iterate over all pids\n    // get name for each via helper function\n    for(int i = 0; i < numberOfProcesses; ++i)\n    {\n        //skip blank pids\n        if(0 == pids[i])\n        {\n            //skip\n            continue;\n        }\n        \n        //get path\n        processPath = getProcessPath(pids[i]);\n        if( (nil == processPath) ||\n            (0 == processPath.length) )\n        {\n            //skip\n            continue;\n        }\n        \n        //no match?\n        if(YES != [processPath.lastPathComponent isEqualToString:processName])\n        {\n            //skip\n            continue;\n        }\n            \n        //save\n        [processes addObject:@{KEY_PROCESS_ID:[NSNumber numberWithInt:pids[i]], KEY_PATH:processPath}];\n        \n    }//all procs\n    \nbail:\n    \n    //free buffer\n    if(NULL != pids)\n    {\n        //free\n        free(pids);\n        pids = NULL;\n    }\n    \n    return processes;\n}\n\n//for login item enable/disable\n// we use the launch services APIs, since replacements don't always work :(\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wdeprecated-declarations\"\n\n//toggle login item\n// either add (install) or remove (uninstall)\nBOOL toggleLoginItem(NSURL* loginItem, int toggleFlag)\n{\n    //flag\n    BOOL wasToggled = NO;\n    \n    //status\n    OSStatus status = !noErr;\n    \n    //login items ref\n    LSSharedFileListRef loginItemsRef = NULL;\n    \n    //login item ref\n    LSSharedFileListItemRef loginItemRef = NULL;\n    \n    //login items\n    CFArrayRef loginItems = NULL;\n    \n    //current login item\n    CFURLRef currentLoginItem = NULL;\n    \n    //get reference to login items\n    loginItemsRef = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);\n    \n    //add (install)\n    if(ACTION_INSTALL_FLAG == toggleFlag)\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"adding login item: %{public}@\", loginItem.path);\n        \n        //add\n        loginItemRef = LSSharedFileListInsertItemURL(loginItemsRef, kLSSharedFileListItemLast, NULL, NULL, (__bridge CFURLRef)(loginItem), NULL, NULL);\n        if(NULL != loginItemRef)\n        {\n            //dbg msg\n            os_log_debug(logHandle, \"login item added\");\n            \n            //release\n            CFRelease(loginItemRef);\n            loginItemRef = NULL;\n        }\n        //failed\n        else\n        {\n            //err msg\n            os_log_error(logHandle, \"ERROR: failed to add login item\");\n            \n            //bail\n            goto bail;\n        }\n        \n        //happy\n        wasToggled = YES;\n    }\n    //remove (uninstall)\n    else\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"removing login item: %{public}@\", loginItem.path);\n        \n        //grab all login items\n        loginItems = LSSharedFileListCopySnapshot(loginItemsRef, nil);\n        \n        //iterate over all login items\n        // look for self(s), then remove it\n        for(id item in (__bridge NSArray *)loginItems)\n        {\n            //get current login item\n            currentLoginItem = LSSharedFileListItemCopyResolvedURL((__bridge LSSharedFileListItemRef)item, 0, NULL);\n            if(NULL == currentLoginItem) continue;\n            \n            //current login item match self?\n            if(YES == [(__bridge NSURL *)currentLoginItem isEqual:loginItem])\n            {\n                //dbg msg\n                os_log_debug(logHandle, \"found match\");\n                \n                //remove\n                if(noErr == (status = LSSharedFileListItemRemove(loginItemsRef, (__bridge LSSharedFileListItemRef)item)))\n                {\n                    //nap\n                    // give some time for event to complete\n                    [NSThread sleepForTimeInterval:1.0f];\n                    \n                    //dbg msg\n                    os_log_debug(logHandle, \"removed login item\");\n                    \n                    //happy\n                    wasToggled = YES;\n                }\n                else\n                {\n                    //err msg\n                    os_log_error(logHandle, \"ERROR: failed to remove login item (%x)\", status);\n                    \n                    //keep trying though\n                    // as might be multiple instances...\n                }\n            }\n            \n            //release\n            CFRelease(currentLoginItem);\n            currentLoginItem = NULL;\n            \n        }//all login items\n        \n    }//remove/uninstall\n    \nbail:\n    \n    //release login items\n    if(NULL != loginItems)\n    {\n        //release\n        CFRelease(loginItems);\n        loginItems = NULL;\n    }\n    \n    //release login ref\n    if(NULL != loginItemsRef)\n    {\n        //release\n        CFRelease(loginItemsRef);\n        loginItemsRef = NULL;\n    }\n    \n    return wasToggled;\n}\n\n//grab date added\n// extracted via 'kMDItemDateAdded'\n// or if that's NULL, then 'kMDItemFSCreationDate'\nNSDate* dateAdded(NSString* file)\n{\n    //date added\n    NSDate* date = nil;\n    \n    //item\n    MDItemRef item = NULL;\n    \n    //attribute names\n    CFArrayRef attributeNames = NULL;\n    \n    //attributes\n    CFDictionaryRef attributes = NULL;\n    \n    //app bundle\n    NSBundle* appBundle = nil;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"extracting 'kMDItemDateAdded' for %{public}@\", file);\n    \n    //try find an app bundle\n    appBundle = findAppBundle(file);\n    if(nil != appBundle)\n    {\n        //init item with app's path\n        item = MDItemCreateWithURL(NULL, (__bridge CFURLRef)appBundle.bundleURL);\n        if(NULL == item)\n        {\n            goto bail;\n        }\n    }\n    //no app bundle\n    // just use item/path as it\n    else\n    {\n        //init item with path\n        item = MDItemCreateWithURL(NULL, (__bridge CFURLRef)[NSURL fileURLWithPath:file]);\n        if(NULL == item)\n        {\n            goto bail;\n        }\n    }\n    \n    //get attribute names\n    attributeNames = MDItemCopyAttributeNames(item);\n    if(NULL == attributeNames)\n    {\n        goto bail;\n    }\n    \n    //get attributes\n    attributes = MDItemCopyAttributes(item, attributeNames);\n    if(NULL == attributes)\n    {\n        goto bail;\n    }\n    \n    //grab date added\n    date = CFBridgingRelease(MDItemCopyAttribute(item, kMDItemDateAdded));\n    if(nil == date)\n    {\n        //dbg msg\n        os_log_debug(logHandle, \"'kMDItemDateAdded' is nil ...falling back to 'kMDItemFSCreationDate'\");\n        \n        //grab date via 'kMDItemFSCreationDate'\n        date = CFBridgingRelease(MDItemCopyAttribute(item, kMDItemFSCreationDate));\n    }\n    \n    //dbg msg\n    os_log_debug(logHandle, \"extacted date, %{public}@, for %{public}@\", date, file);\n\nbail:\n    \n    //free attributes\n    if(NULL != attributes)\n    {\n        CFRelease(attributes);\n    }\n    \n    //free attribute names\n    if(NULL != attributeNames)\n    {\n        CFRelease(attributeNames);\n    }\n    \n    //free item\n    if(NULL != item)\n    {\n        CFRelease(item);\n    }\n    \n    return date;\n}\n\n\n#pragma clang diagnostic pop\n\n\n//sha256\n// as string\nNSMutableString* hashFile(NSString* path) {\n    \n    NSData* contents = [NSData dataWithContentsOfFile:path];\n    if (!contents)\n    {\n        os_log_error(logHandle, \"ERROR: failed to read in %{public}@ for hashing\", path);\n        return nil;\n    }\n    \n    unsigned char digest[CC_SHA256_DIGEST_LENGTH];\n    CC_SHA256(contents.bytes, (CC_LONG)contents.length, digest);\n    \n    NSMutableString* hash = [NSMutableString stringWithCapacity:CC_SHA256_DIGEST_LENGTH * 2];\n    for (int i = 0; i < CC_SHA256_DIGEST_LENGTH; i++) {\n        [hash appendFormat:@\"%02x\", digest[i]];\n    }\n    \n    return hash;\n}\n\n//get parent pid\npid_t getParent(int pid)\n{\n    //parent id\n    pid_t parentID = -1;\n    \n    //kinfo_proc struct\n    struct kinfo_proc processStruct;\n    \n    //size\n    size_t procBufferSize = sizeof(processStruct);\n    \n    //mib\n    const u_int mibLength = 4;\n    \n    //syscall result\n    int sysctlResult = -1;\n    \n    //init mib\n    int mib[mibLength] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid};\n    \n    //clear buffer\n    memset(&processStruct, 0x0, procBufferSize);\n    \n    //make syscall\n    sysctlResult = sysctl(mib, mibLength, &processStruct, &procBufferSize, NULL, 0);\n    \n    //check if got ppid\n    if( (noErr == sysctlResult) &&\n        (0 != procBufferSize) )\n    {\n        //save ppid\n        parentID = processStruct.kp_eproc.e_ppid;\n        \n        //dbg msg\n        os_log_debug(logHandle, \"extracted parent ID %d for process: %d\", parentID, pid);\n    }\n    \n    return parentID;\n}\n\n\n//loads a framework\n// note: assumes it is in 'Framework' dir\nNSBundle* loadFramework(NSString* name)\n{\n    //handle\n    NSBundle* framework = nil;\n    \n    //framework path\n    NSString* path = nil;\n    \n    //init path\n    path = [NSString stringWithFormat:@\"%@/../Frameworks/%@\", [NSProcessInfo.processInfo.arguments.firstObject stringByDeletingLastPathComponent], name];\n    \n    //standardize path\n    path = [path stringByStandardizingPath];\n    \n    //init framework (bundle)\n    framework = [NSBundle bundleWithPath:path];\n    if(NULL == framework)\n    {\n        //bail\n        goto bail;\n    }\n    \n    //load framework\n    if(YES != [framework loadAndReturnError:nil])\n    {\n        //bail\n        goto bail;\n    }\n    \nbail:\n    \n    return framework;\n}\n\n//dark mode?\nBOOL isDarkMode(void)\n{\n    //check 'AppleInterfaceStyle'\n    return [[[NSUserDefaults standardUserDefaults] stringForKey:@\"AppleInterfaceStyle\"] isEqualToString:@\"Dark\"];\n}\n\n//check if something is nil\n// if so, return a default ('unknown') value\nNSString* valueForStringItem(NSString* item)\n{\n    return (nil != item) ? item : NSLocalizedString(@\"unknown\", @\"unknown\");\n}\n\n//show an alert\nNSModalResponse showAlert(NSAlertStyle style, NSString* messageText, NSString* informativeText, NSArray* buttons)\n{\n    //alert\n    NSAlert* alert = nil;\n    \n    //response\n    NSModalResponse response = 0;\n    \n    //init alert\n    alert = [[NSAlert alloc] init];\n    \n    //set style\n    alert.alertStyle = style;\n    \n    //main text\n    alert.messageText = messageText;\n    \n    //add details\n    if(nil != informativeText)\n    {\n        //details\n        alert.informativeText = informativeText;\n    }\n    \n    //add buttons\n    for(NSString* title in buttons)\n    {\n        //add button\n        [alert addButtonWithTitle:title];\n    }\n\n    //make first button, first responder\n    alert.buttons[0].keyEquivalent = @\"\\r\";\n    \n    //center\n    [alert.window center];\n    \n    //foreground\n    [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];\n    \n    //activate\n    if(@available(macOS 14.0, *)) {\n        [NSApp activate];\n    }\n    else\n    {\n        [NSApp activateIgnoringOtherApps:YES];\n    }\n    \n    //(re)make front\n    [[NSRunningApplication currentApplication] activateWithOptions:(NSApplicationActivateAllWindows | NSApplicationActivateIgnoringOtherApps)];\n    \n    //show\n    response = [alert runModal];\n    \n    //(re)set activation policy\n    [((AppDelegate*)[[NSApplication sharedApplication] delegate]) setActivationPolicy];\n    \n    return response;\n}\n\n//get audit token for pid\nNSData* tokenForPid(pid_t pid)\n{\n    //audit token\n    NSData* token = nil;\n    \n    //task's token\n    audit_token_t taskToken = {0};\n    \n    //task\n    task_name_t task = 0;\n    \n    //status\n    kern_return_t status = !KERN_SUCCESS;\n\n    //size\n    mach_msg_type_number_t size = TASK_AUDIT_TOKEN_COUNT;\n    \n    //clear\n    memset(&taskToken, 0x0, sizeof(audit_token_t));\n    \n    //dbg msg\n    os_log_debug(logHandle, \"retrieving audit token for %d\", pid);\n    \n    //get task for process\n    status = task_name_for_pid(mach_task_self(), pid, &task);\n    if(KERN_SUCCESS != status)\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: 'task_name_for_pid' failed with %x\", status);\n        \n        //bail\n        goto bail;\n    }\n    \n    //now get task's audit token\n    status = task_info(task, TASK_AUDIT_TOKEN, (task_info_t)&taskToken, &size);\n    if(KERN_SUCCESS != status)\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: 'task_info' failed with %x\", status);\n        \n        //bail\n        goto bail;\n    }\n    \n    //capture\n    token = [NSData dataWithBytes:&taskToken length:sizeof(audit_token_t)];\n    \n    //dbg msg\n    os_log_debug(logHandle, \"retrieved audit token\");\n    \nbail:\n    \n    //cleanup task\n    if(0 != task)\n    {\n        //cleanup\n        mach_port_deallocate(mach_task_self(), task);\n        task = 0;\n    }\n\n    return token;\n}\n\n//given an ip address\n// reverse resolves it\nNSArray* resolveAddress(NSString* ipAddr)\n{\n    //hints\n    struct addrinfo hints = {0};\n    \n    //result\n    struct addrinfo *result = NULL;\n    \n    //address\n    CFDataRef address = {0};\n    \n    //host\n    CFHostRef host = NULL;\n    \n    //error\n    CFStreamError streamError = {0};\n    \n    //(resolved) host names\n    NSArray* hostNames = nil;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"(attempting to) reverse resolve %{public}@\", ipAddr);\n    \n    //clear hints\n    memset(&hints, 0x0, sizeof(hints));\n    \n    //init flags\n    hints.ai_flags = AI_NUMERICHOST;\n    \n    //init family\n    hints.ai_family = PF_UNSPEC;\n    \n    //init type\n    hints.ai_socktype = SOCK_STREAM;\n    \n    //init proto\n    hints.ai_protocol = 0;\n    \n    //get addr info\n    if(0 != getaddrinfo(ipAddr.UTF8String, NULL, &hints, &result))\n    {\n        goto bail;\n    }\n    \n    //convert to data\n    address = CFDataCreate(NULL, (UInt8 *)result->ai_addr, result->ai_addrlen);\n    if(NULL == address)\n    {\n        goto bail;\n    }\n    \n    //create host\n    host = CFHostCreateWithAddress(kCFAllocatorDefault, address);\n    if(host == nil)\n    {\n        goto bail;\n    }\n    \n    //resolve\n    if(YES != CFHostStartInfoResolution(host, kCFHostNames, &streamError))\n    {\n        goto bail;\n    }\n    \n    //capture\n    hostNames = (__bridge NSArray *)(CFHostGetNames(host, NULL));\n    \nbail:\n    \n    //free address\n    if(NULL != address)\n    {\n        //free\n        CFRelease(address);\n        address = NULL;\n    }\n    \n    //free host\n    if(NULL != host)\n    {\n        //free\n        CFRelease(host);\n        host = NULL;\n    }\n    \n    //free result\n    if(NULL != result)\n    {\n        //free\n        freeaddrinfo(result);\n        result = NULL;\n    }\n    \n    return hostNames;\n}\n\n//process alive?\nBOOL isAlive(pid_t processID)\n{\n    //flag\n    BOOL isAlive = YES;\n    \n    //reset errno\n    errno = 0;\n    \n    //'management info base' array\n    int mib[4] = {0};\n    \n    //kinfo proc\n    struct kinfo_proc procInfo = {0};\n    \n    //try 'kill' with 0\n    // no harm done, but will fail with 'ESRCH' if process is dead\n    kill(processID, 0);\n    \n    //dead proc\n    // 'ESRCH' ->'No such process'\n    if(ESRCH == errno)\n    {\n        //dead\n        isAlive = NO;\n        \n        //bail\n        goto bail;\n    }\n    \n    //size\n    size_t size = 0;\n    \n    //init mib\n    mib[0] = CTL_KERN;\n    mib[1] = KERN_PROC;\n    mib[2] = KERN_PROC_PID;\n    mib[3] = processID;\n    \n    //init size\n    size = sizeof(procInfo);\n\n    //get task's flags\n    // allows to check for zombies\n    if(0 == sysctl(mib, sizeof(mib)/sizeof(*mib), &procInfo, &size, NULL, 0))\n    {\n        //check for zombies\n        if(SZOMB == ((procInfo.kp_proc.p_stat) & SZOMB))\n        {\n            //dead\n            isAlive = NO;\n            \n            //bail\n            goto bail;\n            \n        }\n    }\n    \nbail:\n    \n    return isAlive;\n}\n\n//check if app is an simulator app\n// for now check 'iPhoneSimulator' and 'AppleTVSimulator'\nBOOL isSimulatorApp(NSString* path)\n{\n    //flag\n    BOOL simulatorApp = NO;\n    \n    //bundle\n    NSBundle* bundle = nil;\n    \n    //supported platforms\n    NSArray* supportedPlatforms = nil;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"checking if %{public}@ is a simulator application\", path);\n    \n    //get bundle\n    bundle = findAppBundle(path);\n    if(nil == bundle) goto bail;\n    \n    //get supported platforms\n    supportedPlatforms = bundle.infoDictionary[@\"CFBundleSupportedPlatforms\"];\n    if(YES != [supportedPlatforms isKindOfClass:[NSArray class]]) goto bail;\n    \n    //dbg msg\n    os_log_debug(logHandle, \"supported platforms: %{public}@\", supportedPlatforms);\n    \n    //sanity check\n    if(0 == supportedPlatforms.count) goto bail;\n    \n    //check if simulator app\n    simulatorApp = [[NSSet setWithArray: supportedPlatforms] isSubsetOfSet: [NSSet setWithArray: @[@\"iPhoneSimulator\", @\"AppleTVSimulator\"]]];\n    \nbail:\n    \n    return simulatorApp;\n}\n\n//was app launched by user\nBOOL launchedByUser(void)\n{\n    //flag\n    BOOL byUser = NO;\n    \n    //parent\n    NSDictionary* parent = nil;\n    \n    //get parent\n    parent = getRealParent(getpid());\n    \n    //parent dock/finder/terminal\n    // ...then assume its user launched\n    if( (YES == [parent[@\"CFBundleIdentifier\"] isEqualTo:@\"com.apple.dock\"]) ||\n        (YES == [parent[@\"CFBundleIdentifier\"] isEqualTo:@\"com.apple.finder\"]) ||\n        (YES == [parent[@\"CFBundleIdentifier\"] isEqualTo:@\"com.apple.Terminal\"]) )\n    {\n        //set flag\n        byUser = YES;\n    }\n    \n    return byUser;\n}\n\n//fade out and close a window\nvoid fadeOut(NSWindow* window, float duration)\n{\n    //animate fade out\n    // and then also close\n    [NSAnimationContext runAnimationGroup:^(NSAnimationContext *context) {\n        \n        //set duration\n        context.duration = duration;\n        \n        //set final alpha\n        [[window animator] setAlphaValue:0.0];\n        \n       } completionHandler:^{\n           \n           //close\n           [window close];\n           \n       }];\n    \n    return;\n}\n\n//matches CS info?\n// with some caveats (e.g. Apple App that was moved to App Store)\nBOOL matchesCSInfo(NSDictionary* csInfo_1, NSDictionary* csInfo_2)\n{\n    //match\n    BOOL matches = NO;\n    \n    //status\n    int status_1 = -1;\n    int status_2 = -1;\n    \n    //signer\n    int signer_1 = -1;\n    int signer_2 = -1;\n    \n    //signing ID\n    NSString* signingID_1 = nil;\n    NSString* signingID_2 = nil;\n    \n    //signing auths\n    NSArray* signingAuths_1 = nil;\n    NSArray* signingAuths_2 = nil;\n    \n    //extract status #1\n    if(nil != csInfo_1[KEY_CS_STATUS])\n    {\n        //extract\n        status_1 = [csInfo_1[KEY_CS_STATUS] intValue];\n    }\n    \n    //extract status #2\n    if(nil != csInfo_2[KEY_CS_STATUS])\n    {\n        //extract\n        status_2 = [csInfo_2[KEY_CS_STATUS] intValue];\n    }\n    \n    //check 0x1\n    // signing status mismatch?\n    if(status_1 != status_2)\n    {\n        //dbg msg\n        os_log_error(logHandle, \"ERROR: code signing mismatch (signing status): %{public}@ / %{public}@\", csInfo_1, csInfo_2);\n        \n        //bail\n        goto bail;\n    }\n    \n    //extract signer #1\n    if(nil != csInfo_1[KEY_CS_SIGNER])\n    {\n        //extract\n        signer_1 = [csInfo_1[KEY_CS_SIGNER] intValue];\n    }\n    \n    //extract signer #2\n    if(nil != csInfo_2[KEY_CS_SIGNER])\n    {\n        //extract\n        signer_2 = [csInfo_2[KEY_CS_SIGNER] intValue];\n    }\n    \n    //check 0x2\n    // signer mismatch?\n    if(signer_1 != signer_2)\n    {\n        //but ingore apple apps that have moved\n        if( (signer_1 == Apple && signer_2 == AppStore) ||\n            (signer_1 == AppStore && signer_2 == Apple) )\n        {\n            //dbg msg\n            os_log_error(logHandle, \"ignoring case where Apple App moved to/from Mac App Store: %{public}@ / %{public}@\", csInfo_1, csInfo_2);\n        }\n        //ok something really changed w/ signers\n        else\n        {\n            //dbg msg\n            os_log_error(logHandle, \"ERROR: code signing mismatch (signer): %{public}@ / %{public}@\", csInfo_1, csInfo_2);\n            \n            //bail\n            goto bail;\n        }\n    }\n    \n    //extract signing ID #1\n    if(nil != csInfo_1[KEY_CS_ID])\n    {\n        //extract\n        signingID_1 = csInfo_1[KEY_CS_ID];\n    }\n    \n    //extract signing ID #2\n    if(nil != csInfo_2[KEY_CS_ID])\n    {\n        //extract\n        signingID_2 = csInfo_2[KEY_CS_ID];\n    }\n    \n    //check 0x3\n    // signing ID mismatch?\n    if( ((nil != signingID_1) || (nil != signingID_2)) &&\n        (YES != [signingID_1 isEqualToString:signingID_2]) )\n    {\n        //dbg msg\n        os_log_error(logHandle, \"ERROR: code signing mismatch (signing ID): %{public}@ / %{public}@\", csInfo_1, csInfo_2);\n        \n        //bail\n        goto bail;\n    }\n    \n    //extract signing auths #1\n    if(nil != csInfo_1[KEY_CS_AUTHS])\n    {\n        //extract\n        signingAuths_1 = csInfo_1[KEY_CS_AUTHS];\n    }\n    \n    //extract match's signing auths #2\n    if(nil != csInfo_2[KEY_CS_AUTHS])\n    {\n        //extract\n        signingAuths_2 = csInfo_2[KEY_CS_AUTHS];\n    }\n    \n    //check 0x4\n    // signing auths mismatch?\n    if( ((nil != signingAuths_1) || (nil != signingAuths_2)) &&\n        (YES != [signingAuths_1 isEqualToArray:signingAuths_2]) )\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: code signing mismatch (signing auths): %{public}@ / %{public}@\", csInfo_1, csInfo_2);\n        \n        //bail\n        goto bail;\n    }\n    \n    //happy\n    matches = YES;\n    \nbail:\n    \n    return matches;\n    \n}\n\n//escape string\nNSString* toEscapedJSON(NSString* input)\n{\n    NSData* data = nil;\n    NSError* error = nil;\n    NSString* output = nil;\n    \n    @try {\n    \n        data = [NSJSONSerialization dataWithJSONObject:input options:NSJSONWritingFragmentsAllowed error:&error];\n        if( (nil == data) ||\n            (nil != error) )\n        {\n            //err msg\n            os_log_error(logHandle, \"ERROR: failed to convert/escape %{public}@ to JSON (error: %{public}@)\", input, error);\n            \n            goto bail;\n        }\n    }\n    @catch(NSException* exception)\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: failed to convert/escape %{public}@ to JSON (exception: %{public}@)\", input, exception);\n        goto bail;\n    }\n    \n    output = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];\n    \nbail:\n    return output;\n}\n\n\n//is process on internal drive?\nBOOL isInternalProcess(NSString *path)\n{\n    NSError* error = nil;\n    NSNumber* isInternal = nil;\n    \n    if(YES != [[NSURL fileURLWithPath:path] getResourceValue:&isInternal forKey:NSURLVolumeIsInternalKey error:&error] || (nil != error))\n    {\n        //err msg\n        os_log_error(logHandle, \"ERROR: 'getResourceValue'/'NSURLVolumeIsInternalKey' failed with %@\", error);\n        \n        goto bail;\n    }\n    \nbail:\n    \n    return isInternal.boolValue;\n}\n"
  },
  {
    "path": "LuLu/Tests/README.md",
    "content": "# LuLu Passive Mode Improvements Tests\n\nThis directory contains tests for the passive mode FQDN rule creation improvements.\n\n## What's Tested\n\n### 🎯 Domain Name Prioritization\n- Prioritizes `flow.URL.host` over `flow.remoteHostname` over `remoteEndpoint.hostname`\n- Ensures rules use domain names like `github.com` instead of IP addresses like `140.82.112.3`\n\n### 🎨 Smart Port Display  \n- Hides common ports (80, 443) for cleaner UI display\n- Shows uncommon ports (8080, 3000, etc.) to highlight important information\n- Preserves full data internally for precise filtering\n\n### 🔗 End-to-End Integration\n- Validates complete flow from network traffic to final rule display\n- Tests real-world scenarios with complex URLs and various port configurations\n\n## Running Tests\n\n```bash\n# Run the complete test suite\n./run_passive_mode_tests.sh\n```\n\n## Test Results\n\n✅ **9/9 tests pass** covering all functionality\n\n### Before/After Examples\n\n| Before (IP-based) | After (Domain-based) |\n|------------------|---------------------|\n| `140.82.112.3:443` | `github.com` |\n| `52.36.184.210:443` | `api.slack.com` |\n| `127.0.0.1:8080` | `localhost:8080` |\n\n## Files\n\n- `test_passive_mode_improvements.m` - Comprehensive test suite\n- `run_passive_mode_tests.sh` - Build and run script\n- `README.md` - This file\n"
  },
  {
    "path": "LuLu/Tests/run_passive_mode_tests.sh",
    "content": "#!/bin/bash\n\n#\n# run_passive_mode_tests.sh\n# Script to compile and run passive mode improvements tests\n#\n\necho \"🚀 Building and running passive mode improvements tests...\"\necho \"========================================================\"\n\n# Set up paths\nSCRIPT_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" && pwd)\"\nTEST_FILE=\"$SCRIPT_DIR/test_passive_mode_improvements.m\"\nTEST_BINARY=\"$SCRIPT_DIR/test_passive_mode_improvements\"\n\n# Check if test file exists\nif [ ! -f \"$TEST_FILE\" ]; then\n    echo \"❌ Error: Test file not found at $TEST_FILE\"\n    exit 1\nfi\n\necho \"📁 Test directory: $SCRIPT_DIR\"\necho \"📄 Test file: $TEST_FILE\"\n\n# Compile the test\necho \"\"\necho \"🔨 Compiling test...\"\nclang -framework Foundation -framework NetworkExtension \\\n      -o \"$TEST_BINARY\" \\\n      \"$TEST_FILE\" \\\n      -Wno-objc-missing-property-synthesis \\\n      -Wno-incomplete-implementation\n\n# Check if compilation succeeded\nif [ $? -ne 0 ]; then\n    echo \"❌ Compilation failed!\"\n    exit 1\nfi\n\necho \"✅ Compilation successful!\"\n\n# Run the test\necho \"\"\necho \"🧪 Running tests...\"\necho \"==================\"\n\"$TEST_BINARY\"\n\n# Capture test result\nTEST_RESULT=$?\n\n# Clean up\necho \"\"\necho \"🧹 Cleaning up...\"\nrm -f \"$TEST_BINARY\"\n\n# Report final result\nif [ $TEST_RESULT -eq 0 ]; then\n    echo \"✅ All tests completed successfully!\"\nelse\n    echo \"❌ Tests failed with exit code $TEST_RESULT\"\nfi\n\nexit $TEST_RESULT\n"
  },
  {
    "path": "LuLu/Tests/test_passive_mode_improvements.m",
    "content": "//\n//  test_complete_functionality.m\n//  LuLu\n//\n//  Complete test suite for hostname prioritization and port display functionality\n//\n\n#import <Foundation/Foundation.h>\n#import <NetworkExtension/NetworkExtension.h>\n\n// Import our constants\n#define VALUE_ANY @\"*\"\n\n// Mock FilterDataProvider interface for testing\n@interface TestFilterDataProvider : NSObject\n- (NSString*)getBestHostnameFromFlow:(NEFilterSocketFlow*)flow;\n@end\n\n@implementation TestFilterDataProvider\n\n// Copy of our implementation for testing\n- (NSString*)getBestHostnameFromFlow:(NEFilterSocketFlow*)flow\n{\n    //best hostname\n    NSString* bestHostname = nil;\n    \n    //remote endpoint\n    NWHostEndpoint* remoteEndpoint = nil;\n    \n    //extract remote endpoint\n    remoteEndpoint = (NWHostEndpoint*)flow.remoteEndpoint;\n    \n    //priority 1: try flow.URL.host (best for domain names)\n    if(nil != flow.URL.host && 0 != flow.URL.host.length)\n    {\n        bestHostname = flow.URL.host;\n        goto bail;\n    }\n    \n    //priority 2: try flow.remoteHostname (macOS 11+)\n    if(@available(macOS 11, *))\n    {\n        if(nil != flow.remoteHostname && 0 != flow.remoteHostname.length)\n        {\n            bestHostname = flow.remoteHostname;\n            goto bail;\n        }\n    }\n    \n    //priority 3: fallback to remoteEndpoint.hostname (may be IP address)\n    if(nil != remoteEndpoint.hostname && 0 != remoteEndpoint.hostname.length)\n    {\n        bestHostname = remoteEndpoint.hostname;\n    }\n    \nbail:\n    \n    return bestHostname;\n}\n\n@end\n\n// Mock Rule class for testing port display\n@interface TestRule : NSObject\n@property (nonatomic, strong) NSString* endpointAddr;\n@property (nonatomic, strong) NSString* endpointPort;\n@end\n\n@implementation TestRule\n@synthesize endpointAddr, endpointPort;\n\n// Port display logic (copied from RulesWindowController.m)\n- (NSString*)displayString {\n    NSString* address = [self.endpointAddr isEqualToString:VALUE_ANY] ? @\"any address\" : self.endpointAddr;\n    NSString* port = [self.endpointPort isEqualToString:VALUE_ANY] ? @\"any port\" : self.endpointPort;\n    \n    // Smart port display (hide common ports 80, 443)\n    if (([self.endpointPort isEqualToString:@\"80\"] || [self.endpointPort isEqualToString:@\"443\"]) &&\n        NO == [self.endpointAddr isEqualToString:VALUE_ANY] &&\n        NO == [self.endpointPort isEqualToString:VALUE_ANY]) {\n        // Hide common ports for cleaner display\n        return address;\n    } else {\n        // Show port for uncommon ports or when using \"any\" values\n        return [NSString stringWithFormat:@\"%@:%@\", address, port];\n    }\n}\n\n@end\n\n// Test helper to create simple flow objects for testing\n@interface TestFlow : NEFilterSocketFlow\n@property (nonatomic, strong) NSURL* URL;\n@property (nonatomic, strong) NSString* remoteHostname;\n@property (nonatomic, strong) NWHostEndpoint* remoteEndpoint;\n@end\n\n@implementation TestFlow\n@synthesize URL, remoteHostname, remoteEndpoint;\n@end\n\nint main(int argc, const char * argv[]) {\n    @autoreleasepool {\n        \n        NSLog(@\"🧪 Complete Functionality Test Suite\");\n        NSLog(@\"===================================\");\n        \n        TestFilterDataProvider* provider = [[TestFilterDataProvider alloc] init];\n        int testsPassed = 0;\n        int totalTests = 0;\n        \n        NSLog(@\"\\n🔍 PART 1: Hostname Prioritization Tests\");\n        NSLog(@\"========================================\");\n        \n        // Test 1: URL host prioritization\n        {\n            totalTests++;\n            NSLog(@\"\\n📋 Test 1: URL host prioritization\");\n            \n            TestFlow* flow = [[TestFlow alloc] init];\n            flow.URL = [NSURL URLWithString:@\"https://github.com/\"];\n            flow.remoteEndpoint = [NWHostEndpoint endpointWithHostname:@\"140.82.112.3\" port:@\"443\"];\n            \n            NSString* result = [provider getBestHostnameFromFlow:flow];\n            \n            if ([result isEqualToString:@\"github.com\"]) {\n                NSLog(@\"✅ PASS: Got '%@' (expected domain name over IP)\", result);\n                testsPassed++;\n            } else {\n                NSLog(@\"❌ FAIL: Got '%@' (expected 'github.com')\", result);\n            }\n        }\n        \n        // Test 2: Remote hostname fallback\n        {\n            totalTests++;\n            NSLog(@\"\\n📋 Test 2: Remote hostname fallback\");\n            \n            TestFlow* flow = [[TestFlow alloc] init];\n            flow.remoteHostname = @\"api.github.com\";\n            flow.remoteEndpoint = [NWHostEndpoint endpointWithHostname:@\"140.82.112.3\" port:@\"443\"];\n            \n            NSString* result = [provider getBestHostnameFromFlow:flow];\n            \n            if ([result isEqualToString:@\"api.github.com\"]) {\n                NSLog(@\"✅ PASS: Got '%@' (expected remote hostname)\", result);\n                testsPassed++;\n            } else {\n                NSLog(@\"❌ FAIL: Got '%@' (expected 'api.github.com')\", result);\n            }\n        }\n        \n        NSLog(@\"\\n🎨 PART 2: Port Display Tests\");\n        NSLog(@\"=============================\");\n        \n        // Test 3: Hide port 443 for HTTPS\n        {\n            totalTests++;\n            NSLog(@\"\\n📋 Test 3: Hide port 443 for HTTPS\");\n            \n            TestRule* rule = [[TestRule alloc] init];\n            rule.endpointAddr = @\"github.com\";\n            rule.endpointPort = @\"443\";\n            \n            NSString* display = [rule displayString];\n            \n            if ([display isEqualToString:@\"github.com\"]) {\n                NSLog(@\"✅ PASS: Display '%@' (hidden port 443)\", display);\n                testsPassed++;\n            } else {\n                NSLog(@\"❌ FAIL: Display '%@' (expected 'github.com')\", display);\n            }\n        }\n        \n        // Test 4: Hide port 80 for HTTP\n        {\n            totalTests++;\n            NSLog(@\"\\n📋 Test 4: Hide port 80 for HTTP\");\n            \n            TestRule* rule = [[TestRule alloc] init];\n            rule.endpointAddr = @\"example.com\";\n            rule.endpointPort = @\"80\";\n            \n            NSString* display = [rule displayString];\n            \n            if ([display isEqualToString:@\"example.com\"]) {\n                NSLog(@\"✅ PASS: Display '%@' (hidden port 80)\", display);\n                testsPassed++;\n            } else {\n                NSLog(@\"❌ FAIL: Display '%@' (expected 'example.com')\", display);\n            }\n        }\n        \n        // Test 5: Show uncommon port 8080\n        {\n            totalTests++;\n            NSLog(@\"\\n📋 Test 5: Show uncommon port 8080\");\n            \n            TestRule* rule = [[TestRule alloc] init];\n            rule.endpointAddr = @\"localhost\";\n            rule.endpointPort = @\"8080\";\n            \n            NSString* display = [rule displayString];\n            \n            if ([display isEqualToString:@\"localhost:8080\"]) {\n                NSLog(@\"✅ PASS: Display '%@' (shown uncommon port)\", display);\n                testsPassed++;\n            } else {\n                NSLog(@\"❌ FAIL: Display '%@' (expected 'localhost:8080')\", display);\n            }\n        }\n        \n        // Test 6: Show port when address is \"any\"\n        {\n            totalTests++;\n            NSLog(@\"\\n📋 Test 6: Show port when address is 'any'\");\n            \n            TestRule* rule = [[TestRule alloc] init];\n            rule.endpointAddr = VALUE_ANY;\n            rule.endpointPort = @\"443\";\n            \n            NSString* display = [rule displayString];\n            \n            if ([display isEqualToString:@\"any address:443\"]) {\n                NSLog(@\"✅ PASS: Display '%@' (shown port for 'any' address)\", display);\n                testsPassed++;\n            } else {\n                NSLog(@\"❌ FAIL: Display '%@' (expected 'any address:443')\", display);\n            }\n        }\n        \n        // Test 7: Show port when port is \"any\"\n        {\n            totalTests++;\n            NSLog(@\"\\n📋 Test 7: Show port when port is 'any'\");\n            \n            TestRule* rule = [[TestRule alloc] init];\n            rule.endpointAddr = @\"github.com\";\n            rule.endpointPort = VALUE_ANY;\n            \n            NSString* display = [rule displayString];\n            \n            if ([display isEqualToString:@\"github.com:any port\"]) {\n                NSLog(@\"✅ PASS: Display '%@' (shown 'any port')\", display);\n                testsPassed++;\n            } else {\n                NSLog(@\"❌ FAIL: Display '%@' (expected 'github.com:any port')\", display);\n            }\n        }\n        \n        NSLog(@\"\\n🔗 PART 3: Integration Tests\");\n        NSLog(@\"============================\");\n        \n        // Test 8: End-to-end domain + port hiding\n        {\n            totalTests++;\n            NSLog(@\"\\n📋 Test 8: End-to-end: domain extraction + port hiding\");\n            \n            // Simulate the full flow: extract hostname from flow, create rule, display\n            TestFlow* flow = [[TestFlow alloc] init];\n            flow.URL = [NSURL URLWithString:@\"https://api.slack.com/api/conversations.list\"];\n            flow.remoteEndpoint = [NWHostEndpoint endpointWithHostname:@\"52.36.184.210\" port:@\"443\"];\n            \n            NSString* hostname = [provider getBestHostnameFromFlow:flow];\n            NSString* port = flow.remoteEndpoint.port;\n            \n            TestRule* rule = [[TestRule alloc] init];\n            rule.endpointAddr = hostname;\n            rule.endpointPort = port;\n            \n            NSString* display = [rule displayString];\n            \n            if ([display isEqualToString:@\"api.slack.com\"]) {\n                NSLog(@\"✅ PASS: Full flow '%@' (domain extracted, port hidden)\", display);\n                NSLog(@\"   • Original: https://api.slack.com/api/conversations.list → 52.36.184.210:443\");\n                NSLog(@\"   • Improved: %@\", display);\n                testsPassed++;\n            } else {\n                NSLog(@\"❌ FAIL: Full flow '%@' (expected 'api.slack.com')\", display);\n            }\n        }\n        \n        // Test 9: Custom port preserved in full flow\n        {\n            totalTests++;\n            NSLog(@\"\\n📋 Test 9: End-to-end: domain extraction + custom port shown\");\n            \n            TestFlow* flow = [[TestFlow alloc] init];\n            flow.URL = [NSURL URLWithString:@\"http://localhost:3000/api\"];\n            flow.remoteEndpoint = [NWHostEndpoint endpointWithHostname:@\"127.0.0.1\" port:@\"3000\"];\n            \n            NSString* hostname = [provider getBestHostnameFromFlow:flow];\n            NSString* port = flow.remoteEndpoint.port;\n            \n            TestRule* rule = [[TestRule alloc] init];\n            rule.endpointAddr = hostname;\n            rule.endpointPort = port;\n            \n            NSString* display = [rule displayString];\n            \n            if ([display isEqualToString:@\"localhost:3000\"]) {\n                NSLog(@\"✅ PASS: Full flow '%@' (domain extracted, custom port shown)\", display);\n                NSLog(@\"   • Original: http://localhost:3000/api → 127.0.0.1:3000\");\n                NSLog(@\"   • Improved: %@\", display);\n                testsPassed++;\n            } else {\n                NSLog(@\"❌ FAIL: Full flow '%@' (expected 'localhost:3000')\", display);\n            }\n        }\n        \n        // Test Results Summary\n        NSLog(@\"\\n🏁 Complete Test Results\");\n        NSLog(@\"========================\");\n        NSLog(@\"Tests Passed: %d/%d\", testsPassed, totalTests);\n        \n        if (testsPassed == totalTests) {\n            NSLog(@\"✅ ALL TESTS PASSED!\");\n            NSLog(@\"\");\n            NSLog(@\"📊 Feature Summary:\");\n            NSLog(@\"  ✅ Domain name prioritization working\");\n            NSLog(@\"  ✅ Port hiding for common ports (80, 443)\");\n            NSLog(@\"  ✅ Port showing for uncommon ports\");\n            NSLog(@\"  ✅ End-to-end functionality verified\");\n            NSLog(@\"\");\n            NSLog(@\"🎯 Before/After Examples:\");\n            NSLog(@\"  Old: 140.82.112.3:443    →  New: github.com\");\n            NSLog(@\"  Old: 52.36.184.210:443   →  New: api.slack.com\");\n            NSLog(@\"  Old: 127.0.0.1:8080      →  New: localhost:8080\");\n            return 0;\n        } else {\n            NSLog(@\"❌ %d tests failed. Please check implementation.\", totalTests - testsPassed);\n            return 1;\n        }\n    }\n}\n"
  },
  {
    "path": "README.md",
    "content": "# LuLu\n\n[简体中文](README_zh-Hans.md) | [正體中文](README_zh-Hant.md)\n\nLuLu is the free open-source macOS firewall:\n\n<p align=\"center\"><img src=\"https://objective-see.com/images/LL/alert.png\"></p>\n\n**Documentation:** \\\nFull details and usage instructions can be found [here](https://objective-see.com/products/lulu.html).\n\n**To Support:** \\\n&#x2764;&nbsp; Love this product and want to support it? Please check out my [patreon page](https://www.patreon.com/objective_see).\n\n<p align=\"center\">\n<a class=\"inlineLink\" href=\"https://www.patreon.com/objective_see\">\n\t\t<img src=\"https://objective-see.com/patreon/images/patreon.jpg\" width=\"700\" style=\"display:block; margin:auto;\"/>\n</a>\n</p>\n"
  },
  {
    "path": "README_zh-Hans.md",
    "content": "# LuLu\n\n[English](README.md) | [正體中文](README_zh-Hant.md)\n\nLuLu 是免费的开源 macOS 防火墙：\n\n<p align=\"center\"><img src=\"https://objective-see.com/images/LL/alert.png\"></p>\n\n**文档：** \\\n可[在此处](https://objective-see.com/products/lulu.html)找到完整的详细信息和使用说明。\n\n**支持：** \\\n&#x2764;&nbsp; 喜欢这个产品并想支持它？请查看我的 [patreon 页面](https://www.patreon.com/objective_see).\n\n<p align=\"center\">\n<a class=\"inlineLink\" href=\"https://www.patreon.com/objective_see\">\n\t\t<img src=\"https://objective-see.com/patreon/images/patreon.jpg\" width=\"700\" style=\"display:block; margin:auto;\"/>\n</a>\n</p>\n"
  },
  {
    "path": "README_zh-Hant.md",
    "content": "# LuLu\n\n[English](README.md) | [简体中文](README_zh-Hans.md)\n\nLuLu 是免費的開源 macOS 防火牆：\n\n<p align=\"center\"><img src=\"https://objective-see.com/images/LL/alert.png\"></p>\n\n** 文件：** \\\n可[在此處](https://objective-see.com/products/lulu.html)找到完整的詳細資訊和使用説明。\n\n**支持：** \\\n&#x2764;&nbsp; 喜歡這個産品並想支持它？請查看我的 [patreon 頁面](https://www.patreon.com/objective_see).\n\n<p align=\"center\">\n<a class=\"inlineLink\" href=\"https://www.patreon.com/objective_see\">\n\t\t<img src=\"https://objective-see.com/patreon/images/patreon.jpg\" width=\"700\" style=\"display:block; margin:auto;\"/>\n</a>\n</p>\n"
  },
  {
    "path": "lulu.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"group:LuLu/LuLu.xcodeproj\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": "lulu.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>IDEDidComputeMac32BitWarning</key>\n\t<true/>\n</dict>\n</plist>\n"
  }
]