Ansariel 2023-11-30 18:45:03 +01:00
commit 508eb80872
12 changed files with 215 additions and 171 deletions

View File

@ -14,8 +14,6 @@ env:
EXTRA_ARGS: -DUSE_FMODSTUDIO=ON -DUSE_KDU=ON --crashreporting
build_secrets_checkout: ${{github.workspace}}/signing
XZ_DEFAULTS: -T0
jobs:
build_matrix:
strategy:
@ -25,21 +23,28 @@ jobs:
addrsize: [64]
runs-on: ${{ matrix.os }}
steps:
- name: Install Bash 4 and GNU sed on Mac
if: runner.os == 'macOS'
run: |
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
brew update
brew install bash
brew install gnu-sed
echo "/usr/local/bin" >> $GITHUB_PATH
echo "$(brew --prefix)/opt/gnu-sed/libexec/gnubin" >> $GITHUB_PATH
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
id: py311
id: py312
with:
python-version: '3.11'
python-version: '3.11.6'
cache: 'pip'
- if: runner.os == 'Windows'
run: |
python3 -m pip install -r requirements.txt --user
echo "$HOME/.local/bin" >> $GITHUB_PATH
- if: runner.os != 'Windows'
- name: Install python requirements
run: |
python3 -m pip install -r requirements.txt
python -m pip install -r requirements.txt
- name: Check python version
run: python -V
@ -54,6 +59,14 @@ jobs:
EOF
shell: bash
- name: Test python3 llsd
run: |
python3 - <<EOF
import llsd
print("Hello from inline Python script!")
EOF
shell: bash
- name: Free Disk Space (Ubuntu)
if: runner.os == 'Linux'
uses: jlumbroso/free-disk-space@main
@ -66,17 +79,6 @@ jobs:
echo "CC=gcc-10" >> $GITHUB_ENV
echo "CXX=g++-10" >> $GITHUB_ENV
- name: Install Bash 4 and GNU sed on Mac
if: runner.os == 'macOS'
run: |
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
brew update
brew install bash
brew install gnu-sed
echo "/usr/local/bin" >> $GITHUB_PATH
echo "$(brew --prefix)/opt/gnu-sed/libexec/gnubin" >> $GITHUB_PATH
- name: Setup rclone and download the folder
uses: beqjanus/setup-rclone@main

View File

@ -1479,9 +1479,9 @@
<key>archive</key>
<map>
<key>hash</key>
<string>3142fccbcc0e2c5a019e3177ef364290</string>
<string>47af788cc447a64e311e3a65b74a9cf9</string>
<key>url</key>
<string>file:///opt/firestorm/kdu-8.3-darwin64-232392239.tar.bz2</string>
<string>file:///opt/firestorm/kdu-8.4.1-darwin64-233220201.tar.bz2</string>
</map>
<key>name</key>
<string>darwin64</string>
@ -1491,9 +1491,9 @@
<key>archive</key>
<map>
<key>hash</key>
<string>e13d6fe708613bb3a5d630c4cdd97a3b</string>
<string>b464a547d5bedcc72e9173d860f40656</string>
<key>url</key>
<string>file:///opt/firestorm/kdu-8.3-linux64-232392238.tar.bz2</string>
<string>file:///opt/firestorm/kdu-8.4.1-linux64-233220158.tar.bz2</string>
</map>
<key>name</key>
<string>linux64</string>
@ -1503,9 +1503,9 @@
<key>archive</key>
<map>
<key>hash</key>
<string>4aa7df19125708580055b42190d2511e</string>
<string>526965ad83ad9ee355b6596f489d82d9</string>
<key>url</key>
<string>file:///c:/cygwin/opt/firestorm/kdu-8.3-windows-232392239.tar.bz2</string>
<string>file:///c:/cygwin/opt/firestorm/kdu-8.4.1-windows-233220159.tar.bz2</string>
</map>
<key>name</key>
<string>windows64</string>

View File

@ -2144,9 +2144,9 @@ if (WINDOWS)
set_target_properties(${VIEWER_BINARY_NAME}
PROPERTIES
# *TODO -reenable this once we get server usage sorted out
LINK_FLAGS "/debug /NODEFAULTLIB:LIBCMT /SUBSYSTEM:WINDOWS /LARGEADDRESSAWARE /LTCG"
LINK_FLAGS_DEBUG "/NODEFAULTLIB:\"LIBCMT;LIBCMTD;MSVCRT\" /INCREMENTAL:NO /LARGEADDRESSAWARE /LTCG"
LINK_FLAGS_RELEASE "/FORCE:MULTIPLE /MAP\"secondlife-bin.MAP\" /OPT:REF /LARGEADDRESSAWARE /LTCG"
LINK_FLAGS "/debug /NODEFAULTLIB:LIBCMT /SUBSYSTEM:WINDOWS /LARGEADDRESSAWARE /LTCG /NOEXP /NOIMPLIB"
LINK_FLAGS_DEBUG "/NODEFAULTLIB:\"LIBCMT;LIBCMTD;MSVCRT\" /INCREMENTAL:NO /LARGEADDRESSAWARE /LTCG /NOEXP /NOIMPLIB"
LINK_FLAGS_RELEASE "/FORCE:MULTIPLE /MAP\"secondlife-bin.MAP\" /OPT:REF /LARGEADDRESSAWARE /LTCG /NOEXP /NOIMPLIB"
)
if(USE_PRECOMPILED_HEADERS)

View File

@ -534,7 +534,7 @@ bool FloaterAO::newSetCallback(const LLSD& notification, const LLSD& response)
if (option == 0)
{
return AOEngine::instance().addSet(newSetName, [this](const LLUUID& new_cat_id)
AOEngine::instance().addSet(newSetName, [this](const LLUUID& new_cat_id)
{
reloading(true);
});
@ -891,14 +891,12 @@ BOOL FloaterAO::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDr
*accept = ACCEPT_YES_MULTI;
if (item && drop)
{
if (AOEngine::instance().addAnimation(mSelectedSet, mSelectedState, item))
{
addAnimation(item->getName());
AOEngine::instance().addAnimation(mSelectedSet, mSelectedState, item);
addAnimation(item->getName());
// TODO: this would be the right thing to do, but it blocks multi drop
// before final release this must be resolved
reloading(true);
}
// TODO: this would be the right thing to do, but it blocks multi drop
// before final release this must be resolved
reloading(true);
}
}
else

View File

@ -55,7 +55,6 @@ AOEngine::AOEngine() :
mInMouselook(false),
mUnderWater(false),
mImportSet(nullptr),
mImportCategory(LLUUID::null),
mAOFolder(LLUUID::null),
mLastMotion(ANIM_AGENT_STAND),
mLastOverriddenMotion(ANIM_AGENT_STAND)
@ -976,61 +975,35 @@ void AOEngine::updateSortOrder(AOSet::AOState* state)
}
}
bool AOEngine::addSet(const std::string& name, inventory_func_type callback, bool reload)
void AOEngine::addSet(const std::string& name, inventory_func_type callback, bool reload)
{
if (mAOFolder.isNull())
{
LL_WARNS("AOEngine") << ROOT_AO_FOLDER << " folder not there yet. Requesting recreation." << LL_ENDL;
tick();
return false;
return;
}
BOOL wasProtected = gSavedPerAccountSettings.getBOOL("LockAOFolders");
gSavedPerAccountSettings.setBOOL("LockAOFolders", FALSE);
LL_DEBUGS("AOEngine") << "adding set folder " << name << LL_ENDL;
gInventory.createNewCategory(mAOFolder, LLFolderType::FT_NONE, name, [callback, wasProtected, reload, this](const LLUUID &new_cat_id)
gInventory.createNewCategory(mAOFolder, LLFolderType::FT_NONE, name, [callback, wasProtected](const LLUUID &new_cat_id)
{
gSavedPerAccountSettings.setBOOL("LockAOFolders", wasProtected);
if (reload)
{
mTimerCollection.enableReloadTimer(true);
}
callback(new_cat_id);
});
return true;
if (reload)
{
mTimerCollection.enableReloadTimer(true);
}
}
bool AOEngine::createAnimationLink(const AOSet* set, AOSet::AOState* state, const LLInventoryItem* item)
bool AOEngine::createAnimationLink(AOSet::AOState* state, const LLInventoryItem* item)
{
LL_DEBUGS("AOEngine") << "Asset ID " << item->getAssetUUID() << " inventory id " << item->getUUID() << " category id " << state->mInventoryUUID << LL_ENDL;
if (state->mInventoryUUID.isNull())
{
LL_DEBUGS("AOEngine") << "no " << state->mName << " folder yet. Creating ..." << LL_ENDL;
gInventory.createNewCategory(set->getInventoryUUID(), LLFolderType::FT_NONE, state->mName);
LL_DEBUGS("AOEngine") << "looking for folder to get UUID ..." << LL_ENDL;
LLUUID newStateFolderUUID;
LLInventoryModel::item_array_t* items;
LLInventoryModel::cat_array_t* cats;
gInventory.getDirectDescendentsOf(set->getInventoryUUID(), cats, items);
if (cats)
{
for (const auto& cat : *cats)
{
if (cat->getName().compare(state->mName) == 0)
{
LL_DEBUGS("AOEngine") << "UUID found!" << LL_ENDL;
newStateFolderUUID = cat->getUUID();
state->mInventoryUUID = newStateFolderUUID;
break;
}
}
}
}
LL_DEBUGS("AOEngine") << "state " << state->mName << " item " << item->getName() << LL_ENDL;
if (state->mInventoryUUID.isNull())
{
@ -1046,7 +1019,7 @@ bool AOEngine::createAnimationLink(const AOSet* set, AOSet::AOState* state, cons
return true;
}
bool AOEngine::addAnimation(const AOSet* set, AOSet::AOState* state, const LLInventoryItem* item, bool reload)
void AOEngine::addAnimation(const AOSet* set, AOSet::AOState* state, const LLInventoryItem* item, bool reload)
{
AOSet::AOAnimation anim;
anim.mAssetUUID = item->getAssetUUID();
@ -1057,14 +1030,47 @@ bool AOEngine::addAnimation(const AOSet* set, AOSet::AOState* state, const LLInv
BOOL wasProtected = gSavedPerAccountSettings.getBOOL("LockAOFolders");
gSavedPerAccountSettings.setBOOL("LockAOFolders", FALSE);
createAnimationLink(set, state, item);
bool success = createAnimationLink(state, item);
gSavedPerAccountSettings.setBOOL("LockAOFolders", wasProtected);
if (reload)
if(success)
{
mTimerCollection.enableReloadTimer(true);
if (reload)
{
mTimerCollection.enableReloadTimer(true);
}
return;
}
// creating the animation link failed, so we need to create a new folder for this state -
// add the animation asset to the queue of animations to insert into the state - this takes
// care of multi animation drag & drop that come in faster than the viewer can create a new
// inventory folder
state->mAddQueue.push_back(item);
// if this is the first queued animation for this state, create the folder asyncronously
if(state->mAddQueue.size() == 1)
{
gInventory.createNewCategory(set->getInventoryUUID(), LLFolderType::FT_NONE, state->mName, [this, state, reload, wasProtected](const LLUUID &new_cat_id)
{
state->mInventoryUUID = new_cat_id;
gSavedPerAccountSettings.setBOOL("LockAOFolders", FALSE);
// add all queued animations to this state's folder and then clear the queue
for (const auto item : state->mAddQueue)
{
createAnimationLink(state, item);
}
state->mAddQueue.clear();
gSavedPerAccountSettings.setBOOL("LockAOFolders", wasProtected);
if (reload)
{
mTimerCollection.enableReloadTimer(true);
}
});
}
return true;
}
bool AOEngine::findForeignItems(const LLUUID& uuid) const
@ -1965,6 +1971,8 @@ bool AOEngine::importNotecard(const LLInventoryItem* item)
if (item->getAssetUUID().notNull())
{
// create the new set with the folder UUID where the notecard is in, so we can reference it
// in the notecard reader, this will later be cleared to make room for the real #AO subfolder
mImportSet = new AOSet(item->getParentUUID());
mImportSet->setName(item->getName());
@ -2033,7 +2041,7 @@ void AOEngine::parseNotecard(const char* buffer)
LL_WARNS("AOEngine") << "buffer==NULL - aborting import" << LL_ENDL;
// NOTE: cleanup is always the same, needs streamlining
delete mImportSet;
mImportSet = 0;
mImportSet = nullptr;
mUpdatedSignal();
return;
}
@ -2044,31 +2052,29 @@ void AOEngine::parseNotecard(const char* buffer)
std::vector<std::string> lines;
LLStringUtil::getTokens(text, lines, "\n");
bool found{ false };
for (const auto& line : lines)
{
if (line.find("Text length ") == 0)
{
found = true;
break;
}
}
auto it = std::find_if(lines.begin(), lines.end(), [](const std::string& line) {
return line.find("Text length ") == 0;
});
if (!found)
{
if (it == lines.end()) {
// Line not found
LLNotificationsUtil::add("AOImportNoText", LLSD());
delete mImportSet;
mImportSet = 0;
mImportSet = nullptr;
mUpdatedSignal();
return;
}
// Line found, 'it' points to the found element
std::size_t found = std::distance(lines.begin(), it) + 1;
// mImportSet->getInventoryUUID() right now contains the folder UUID where the notecard is in
LLViewerInventoryCategory* importCategory = gInventory.getCategory(mImportSet->getInventoryUUID());
if (!importCategory)
{
LLNotificationsUtil::add("AOImportNoFolder", LLSD());
delete mImportSet;
mImportSet = 0;
mImportSet = nullptr;
mUpdatedSignal();
return;
}
@ -2077,16 +2083,15 @@ void AOEngine::parseNotecard(const char* buffer)
LLInventoryModel::cat_array_t* dummy;
LLInventoryModel::item_array_t* items;
gInventory.getDirectDescendentsOf(mImportSet->getInventoryUUID(), dummy, items);
for (auto index = 0; index < items->size(); ++index)
{
animationMap[items->at(index)->getName()] = items->at(index)->getUUID();
LL_DEBUGS("AOEngine") << "animation " << items->at(index)->getName() <<
" has inventory UUID " << animationMap[items->at(index)->getName()] << LL_ENDL;
}
gInventory.getDirectDescendentsOf(mImportSet->getInventoryUUID(), dummy, items);
for (auto& item : *items)
{
animationMap[item->getName()] = item->getUUID();
LL_DEBUGS("AOEngine") << "animation " << item->getName() << " has inventory UUID " << animationMap[item->getName()] << LL_ENDL;
}
// [ State ]Anim1|Anim2|Anim3
for (auto index = found + 1; index < lines.size(); ++index)
for (auto index = found; index < lines.size(); ++index)
{
std::string line = lines[index];
@ -2169,6 +2174,8 @@ void AOEngine::parseNotecard(const char* buffer)
return;
}
// clear out set UUID so processImport() knows we need to create a new folder for it
mImportSet->setInventoryUUID(LLUUID::null);
mTimerCollection.enableImportTimer(true);
mImportRetryCount = 0;
processImport(false);
@ -2176,74 +2183,87 @@ void AOEngine::parseNotecard(const char* buffer)
void AOEngine::processImport(bool from_timer)
{
if (mImportCategory.isNull())
if (mImportSet->getInventoryUUID().isNull())
{
bool success = addSet(mImportSet->getName(), [this, from_timer](const LLUUID& new_cat_id)
// create new inventory folder for this AO set, the next timer tick should pick it up
addSet(mImportSet->getName(), [this](const LLUUID& new_cat_id)
{
mImportCategory = new_cat_id;
mImportSet->setInventoryUUID(mImportCategory);
bool allComplete = true;
for (S32 index = 0; index < AOSet::AOSTATES_MAX; ++index)
{
AOSet::AOState* state = mImportSet->getState(index);
if (!state->mAnimations.empty())
{
allComplete = false;
LL_DEBUGS("AOEngine") << "state " << state->mName << " still has animations to link." << LL_ENDL;
for (auto animationIndex = state->mAnimations.size() - 1; animationIndex >= 0; --animationIndex)
{
LL_DEBUGS("AOEngine") << "linking animation " << state->mAnimations[animationIndex].mName << LL_ENDL;
if (createAnimationLink(mImportSet, state, gInventory.getItem(state->mAnimations[animationIndex].mInventoryUUID)))
{
LL_DEBUGS("AOEngine") << "link success, size " << state->mAnimations.size() << ", removing animation "
<< (*(state->mAnimations.begin() + animationIndex)).mName << " from import state" << LL_ENDL;
state->mAnimations.erase(state->mAnimations.begin() + animationIndex);
LL_DEBUGS("AOEngine") << "deleted, size now: " << state->mAnimations.size() << LL_ENDL;
}
else
{
LLSD args;
args["NAME"] = state->mAnimations[animationIndex].mName;
LLNotificationsUtil::add("AOImportLinkFailed", args);
}
}
}
}
if (allComplete)
{
mTimerCollection.enableImportTimer(false);
mOldImportSets.push_back(mImportSet); //<ND/> FIRE-3801; Cannot delete here, or LLInstanceTracker gets upset. Just remember and delete mOldImportSets once we can.
mImportSet = nullptr;
mImportCategory.setNull();
reload(from_timer);
}
mImportSet->setInventoryUUID(new_cat_id);
}, false);
if (!success)
mImportRetryCount++;
// if it takes this long to create a new inventoey category, there might be something wrong,
// so give some user feedback at first
if (mImportRetryCount == 2)
{
mImportRetryCount++;
if (mImportRetryCount == 5)
{
// NOTE: cleanup is the same as at the end of this function. Needs streamlining.
mTimerCollection.enableImportTimer(false);
delete mImportSet;
mImportSet = nullptr;
mImportCategory.setNull();
mUpdatedSignal();
LLSD args;
args["NAME"] = mImportSet->getName();
LLNotificationsUtil::add("AOImportAbortCreateSet", args);
}
else
{
LLSD args;
args["NAME"] = mImportSet->getName();
LLNotificationsUtil::add("AOImportRetryCreateSet", args);
}
LLSD args;
args["NAME"] = mImportSet->getName();
LLNotificationsUtil::add("AOImportRetryCreateSet", args);
return;
}
// by now there clearly is something wrong, so stop trying
else if (mImportRetryCount == 5)
{
// NOTE: cleanup is the same as at the end of this function. Needs streamlining.
mTimerCollection.enableImportTimer(false);
delete mImportSet;
mImportSet = nullptr;
mUpdatedSignal();
LLSD args;
args["NAME"] = mImportSet->getName();
LLNotificationsUtil::add("AOImportAbortCreateSet", args);
}
return;
}
bool allComplete = true;
for (S32 index = 0; index < AOSet::AOSTATES_MAX; ++index)
{
AOSet::AOState* state = mImportSet->getState(index);
if (!state->mAnimations.empty())
{
allComplete = false;
LL_DEBUGS("AOEngine") << "state " << state->mName << " still has animations to link." << LL_ENDL;
gInventory.createNewCategory(mImportSet->getInventoryUUID(), LLFolderType::FT_NONE, state->mName, [this, state](const LLUUID& new_cat_id)
{
LL_DEBUGS("AOEngine") << "new_cat_id: " << new_cat_id << LL_ENDL;
state->mInventoryUUID = new_cat_id;
S32 animationIndex = state->mAnimations.size() - 1;
while (!state->mAnimations.empty())
{
LL_DEBUGS("AOEngine") << "linking animation " << state->mAnimations[animationIndex].mName << LL_ENDL;
if (createAnimationLink(state, gInventory.getItem(state->mAnimations[animationIndex].mInventoryUUID)))
{
LL_DEBUGS("AOEngine") << "link success, size " << state->mAnimations.size() << ", removing animation "
<< state->mAnimations[animationIndex].mName << " from import state" << LL_ENDL;
state->mAnimations.pop_back();
LL_DEBUGS("AOEngine") << "deleted, size now: " << state->mAnimations.size() << LL_ENDL;
}
else
{
LLSD args;
args["NAME"] = state->mAnimations[animationIndex].mName;
LLNotificationsUtil::add("AOImportLinkFailed", args);
}
animationIndex--;
}
LL_DEBUGS("AOEngine") << "exiting lambda" << LL_ENDL;
});
}
}
if (allComplete)
{
mTimerCollection.enableImportTimer(false);
mOldImportSets.push_back(mImportSet); //<ND/> FIRE-3801; Cannot delete here, or LLInstanceTracker gets upset. Just remember and delete mOldImportSets once we can.
mImportSet = nullptr;
reload(from_timer);
LLNotificationsUtil::add("AOImportComplete");
}
}

View File

@ -106,10 +106,10 @@ class AOEngine
const LLUUID& getAOFolder() const;
bool addSet(const std::string& name, inventory_func_type callback, bool reload = true);
void addSet(const std::string& name, inventory_func_type callback, bool reload = true);
bool removeSet(AOSet* set);
bool addAnimation(const AOSet* set, AOSet::AOState* state, const LLInventoryItem* item, bool reload = true);
void addAnimation(const AOSet* set, AOSet::AOState* state, const LLInventoryItem* item, bool reload = true);
bool removeAnimation(const AOSet* set, AOSet::AOState* state, S32 index);
void checkSitCancel();
void checkBelowWater(bool check_underwater);
@ -176,7 +176,7 @@ class AOEngine
void saveSet(const AOSet* set);
void saveState(const AOSet::AOState* state);
bool createAnimationLink(const AOSet* set, AOSet::AOState* state, const LLInventoryItem* item);
bool createAnimationLink(AOSet::AOState* state, const LLInventoryItem* item);
bool findForeignItems(const LLUUID& uuid) const;
void purgeFolder(const LLUUID& uuid) const;
@ -217,7 +217,6 @@ class AOEngine
AOSet* mImportSet;
std::vector<AOSet*> mOldImportSets;
LLUUID mImportCategory;
S32 mImportRetryCount;
boost::signals2::connection mRegionChangeConnection;

View File

@ -27,6 +27,8 @@
#include "lleventtimer.h"
class LLInventoryItem;
class AOSet
: public LLEventTimer
{
@ -78,6 +80,7 @@ class AOSet
{
std::string mName;
std::vector<std::string> mAlternateNames;
std::vector<const LLInventoryItem*> mAddQueue;
LLUUID mRemapID;
bool mCycle;
bool mRandom;

View File

@ -110,9 +110,13 @@
#include "llavatarname.h"
#include "llavatarnamecache.h"
#include "llcorehttputil.h"
#include "llfloater.h"
#include "llformat.h"
#include "llmatrix4a.h"
#include "llpanel.h"
#include "lluictrl.h"
#include "llvector4a.h"
#include "llview.h"
#include <boost/array.hpp>
#include <boost/bind.hpp>
#include <boost/filesystem.hpp>
@ -131,6 +135,6 @@
#include <boost/function/function1.hpp>
#include <boost/unordered_map.hpp>
#include <boost/unordered_set.hpp>
#include <vector>
#endif

View File

@ -10674,6 +10674,13 @@ Remove AO set "[AO_SET_NAME]" from the list?
The animation overrider found at least one item that did not belong in the configuration. Please check your &quot;Lost and Found&quot; folder for items that were moved out of the animation overrider configuration.
</notification>
<notification
icon="notifytip.tga"
name="AOImportComplete"
type="notifytip">
Animation Overrider notecard import complete!
</notification>
<notification
icon="notifytip.tga"
name="AOImportSetAlreadyExists"

View File

@ -4176,6 +4176,9 @@ Le nom ne peut contenir que des caractères ASCII, sauf ":" et "|".
<notification name="AOForeignItemsFound">
L'AO a trouvé au moins un élément qui n'avait pas sa place dans la configuration. Veuillez vérifier dans votre dossier "Objets trouvés" les éléments qui ont été déplacés hors de la configuration de l'AO.
</notification>
<notification name="AOImportComplete">
L'importation de la notice d'AO est terminée !
</notification>
<notification name="AOImportSetAlreadyExists">
Un ensemble d'animations portant ce nom existe déjà.
</notification>

View File

@ -3967,6 +3967,9 @@ Nazwa może zawierać tylko znaki ASCII, za wyjątkiem ":" oraz "|".
Usunąć zestaw AO "[AO_SET_NAME]" z listy?
<usetemplate name="okcancelbuttons" notext="Anuluj" yestext="Usuń"/>
</notification>
<notification name="AOImportComplete">
Importowanie notki dla Animatora zakończone!
</notification>
<notification name="AOImportSetAlreadyExists">
Zestaw animacji o tej nazwie już istnieje.
</notification>

View File

@ -53,8 +53,13 @@ viewer_dir = os.path.dirname(__file__)
# indra.util.llmanifest under their system Python!
sys.path.insert(0, os.path.join(viewer_dir, os.pardir, "lib", "python"))
from indra.util.llmanifest import LLManifest, main, path_ancestors, CHANNEL_VENDOR_BASE, RELEASE_CHANNEL, ManifestError, MissingError
import llsd
# <FS:Beq> try to work around weird Mac build issue that seems to find the wrong python
#import llsd
try:
import llsd
except ImportError:
from llbase import llsd
# </FS:Beq>
class ViewerManifest(LLManifest,FSViewerManifest):
def is_packaging_viewer(self):
# Some commands, files will only be included