text:
//
// Copyright (C) 2013-2016 LunarG, Inc.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//    Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
//
//    Redistributions in binary form must reproduce the above
//    copyright notice, this list of conditions and the following
//    disclaimer in the documentation and/or other materials provided
//    with the distribution.
//
//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
//    contributors may be used to endorse or promote products derived
//    from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//

#if !defined(GLSLANG_WEB)

#include "../Include/Common.h"
#include "reflection.h"
#include "LiveTraverser.h"
#include "localintermediate.h"

#include "gl_types.h"

//
// Grow the reflection database through a friend traverser class of TReflection and a
// collection of functions to do a liveness traversal that note what uniforms are used
// in semantically non-dead code.
//
// Can be used multiple times, once per stage, to grow a program reflection.
//
// High-level algorithm for one stage:
//
// 1. Put the entry point on the list of live functions.
//
// 2. Traverse any live function, while skipping if-tests with a compile-time constant
//    condition of false, and while adding any encountered function calls to the live
//    function list.
//
//    Repeat until the live function list is empty.
//
// 3. Add any encountered uniform variables and blocks to the reflection database.
//
// Can be attempted with a failed link, but will return false if recursion had been detected, or
// there wasn't exactly one entry point.
//

namespace glslang {

//
// The traverser: mostly pass through, except
//  - processing binary nodes to see if they are dereferences of an aggregates to track
//  - processing symbol nodes to see if they are non-aggregate objects to track
//
// This ignores semantically dead code by using TLiveTraverser.
//
// This is in the glslang namespace directly so it can be a friend of TReflection.
//

class TReflectionTraverser : public TIntermTraverser {
public:
    TReflectionTraverser(const TIntermediate& i, TReflection& r) :
	                     TIntermTraverser(), intermediate(i), reflection(r), updateStageMasks(true) { }

    virtual bool visitBinary(TVisit, TIntermBinary* node);
    virtual void visitSymbol(TIntermSymbol* base);

    // Add a simple reference to a uniform variable to the uniform database, no dereference involved.
    // However, no dereference doesn't mean simple... it could be a complex aggregate.
    void addUniform(const TIntermSymbol& base)
    {
        if (processedDerefs.find(&base) == processedDerefs.end()) {
            processedDerefs.insert(&base);

            int blockIndex = -1;
            int offset     = -1;
            TList<TIntermBinary*> derefs;
            TString baseName = base.getName();

            if (base.getType().getBasicType() == EbtBlock) {
                offset = 0;
                bool anonymous = IsAnonymous(baseName);
                const TString& blockName = base.getType().getTypeName();

                if (!anonymous)
                    baseName = blockName;
                else
                    baseName = "";

                blockIndex = addBlockName(blockName, base.getType(), intermediate.getBlockSize(base.getType()));
            }

            // Use a degenerate (empty) set of dereferences to immediately put as at the end of
            // the dereference change expected by blowUpActiveAggregate.
            blowUpActiveAggregate(base.getType(), baseName, derefs, derefs.end(), offset, blockIndex, 0, -1, 0,
                                    base.getQualifier().storage, updateStageMasks);
        }
    }

    void addPipeIOVariable(const TIntermSymbol& base)
    {
        if (processedDerefs.find(&base) == processedDerefs.end()) {
            processedDerefs.insert(&base);

            const TString &name = base.getName();
            const TType &type = base.getType();
            const bool input = base.getQualifier().isPipeInput();

            TReflection::TMapIndexToReflection &ioItems =
                input ? reflection.indexToPipeInput : reflection.indexToPipeOutput;

            TReflection::TNameToIndex &ioMapper =
                input ? reflection.pipeInNameToIndex : reflection.pipeOutNameToIndex;

            if (reflection.options & EShReflectionUnwrapIOBlocks) {
                bool anonymous = IsAnonymous(name);

                TString baseName;
                if (type.getBasicType() == EbtBlock) {
                    baseName = anonymous ? TString() : type.getTypeName();
                } else {
                    baseName = anonymous ? TString() : name;
                }

                // by convention if this is an arrayed block we ignore the array in the reflection
                if (type.isArray() && type.getBasicType() == EbtBlock) {
                    blowUpIOAggregate(input, baseName, TType(type, 0));
                } else {
                    blowUpIOAggregate(input, baseName, type);
                }
            } else {
                TReflection::TNameToIndex::const_iterator it = ioMapper.find(name.c_str());
                if (it == ioMapper.end()) {
                    // seperate pipe i/o params from uniforms and blocks
                    // in is only for input in first stage as out is only for last stage. check traverse in call stack.
                    ioMapper[name.c_str()] = static_cast<int>(ioItems.size());
                    ioItems.push_back(
                        TObjectReflection(name.c_str(), type, 0, mapToGlType(type), mapToGlArraySize(type), 0));
                    EShLanguageMask& stages = ioItems.back().stages;
                    stages = static_cast<EShLanguageMask>(stages | 1 << intermediate.getStage());
                } else {
                    EShLanguageMask& stages = ioItems[it->second].stages;
                    stages = static_cast<EShLanguageMask>(stages | 1 << intermediate.getStage());
                }
            }
        }
    }

    // Lookup or calculate the offset of all block members at once, using the recursively
    // defined block offset rules.
    void getOffsets(const TType& type, TVector<int>& offsets)
    {
        const TTypeList& memberList = *type.getStruct();
        int memberSize = 0;
        int offset = 0;

        for (size_t m = 0; m < offsets.size(); ++m) {
            // if the user supplied an offset, snap to it now
            if (memberList[m].type->getQualifier().hasOffset())
                offset = memberList[m].type->getQualifier().layoutOffset;

            // calculate the offset of the next member and align the current offset to this member
            intermediate.updateOffset(type, *memberList[m].type, offset, memberSize);

            // save the offset of this member
            offsets[m] = offset;

            // update for the next member
            offset += memberSize;
        }
    }

    // Calculate the stride of an array type
    int getArrayStride(const TType& baseType, const TType& type)
    {
        int dummySize;
        int stride;

        // consider blocks to have 0 stride, so that all offsets are relative to the start of their block
        if (type.getBasicType() == EbtBlock)
            return 0;

        TLayoutMatrix subMatrixLayout = type.getQualifier().layoutMatrix;
        intermediate.getMemberAlignment(type, dummySize, stride,
                                        baseType.getQualifier().layoutPacking,
                                        subMatrixLayout != ElmNone
                                            ? subMatrixLayout == ElmRowMajor
                                            : baseType.getQualifier().layoutMatrix == ElmRowMajor);

        return stride;
    }

    // count the total number of leaf members from iterating out of a block type
    int countAggregateMembers(const TType& parentType)
    {
        if (! parentType.isStruct())
            return 1;

        const bool strictArraySuffix = (reflection.options & EShReflectionStrictArraySuffix);

        bool blockParent = (parentType.getBasicType() == EbtBlock && parentType.getQualifier().storage == EvqBuffer);

        const TTypeList &memberList = *parentType.getStruct();

        int ret = 0;

        for (size_t i = 0; i < memberList.size(); i++)
        {
            const TType &memberType = *memberList[i].type;
            int numMembers = countAggregateMembers(memberType);
            // for sized arrays of structs, apply logic to expand out the same as we would below in
            // blowUpActiveAggregate
            if (memberType.isArray() && ! memberType.getArraySizes()->hasUnsized() && memberType.isStruct()) {
                if (! strictArraySuffix || ! blockParent)
                    numMembers *= memberType.getArraySizes()->getCumulativeSize();
            }
            ret += numMembers;
        }

        return ret;
    }

    // Traverse the provided deref chain, including the base, and
    // - build a full reflection-granularity name, array size, etc. entry out of it, if it goes down to that granularity
    // - recursively expand any variable array index in the middle of that traversal
    // - recursively expand what's left at the end if the deref chain did not reach down to reflection granularity
    //
    // arraySize tracks, just for the final dereference in the chain, if there was a specific known size.
    // A value of 0 for arraySize will mean to use the full array's size.
    void blowUpActiveAggregate(const TType& baseType, const TString& baseName, const TList<TIntermBinary*>& derefs,
                               TList<TIntermBinary*>::const_iterator deref, int offset, int blockIndex, int arraySize,
                               int topLevelArraySize, int topLevelArrayStride, TStorageQualifier baseStorage, bool active)
    {
        // when strictArraySuffix is enabled, we closely follow the rules from ARB_program_interface_query.
        // Broadly:
        // * arrays-of-structs always have a [x] suffix.
        // * with array-of-struct variables in the root of a buffer block, only ever return [0].
        // * otherwise, array suffixes are added whenever we iterate, even if that means expanding out an array.
        const bool strictArraySuffix = (reflection.options & EShReflectionStrictArraySuffix);

        // is this variable inside a buffer block. This flag is set back to false after we iterate inside the first array element.
        bool blockParent = (baseType.getBasicType() == EbtBlock && baseType.getQualifier().storage == EvqBuffer);

        // process the part of the dereference chain that was explicit in the shader
        TString name = baseName;
        const TType* terminalType = &baseType;
        for (; deref != derefs.end(); ++deref) {
            TIntermBinary* visitNode = *deref;
            terminalType = &visitNode->getType();
            int index;
            switch (visitNode->getOp()) {
            case EOpIndexIndirect: {
                int stride = getArrayStride(baseType, visitNode->getLeft()->getType());

                if (topLevelArrayStride == 0)
                    topLevelArrayStride = stride;

                // Visit all the indices of this array, and for each one add on the remaining dereferencing
                for (int i = 0; i < std::max(visitNode->getLeft()->getType().getOuterArraySize(), 1); ++i) {
                    TString newBaseName = name;
                    if (terminalType->getBasicType() == EbtBlock) {}
                    else if (strictArraySuffix && blockParent)
                        newBaseName.append(TString("[0]"));
                    else if (strictArraySuffix || baseType.getBasicType() != EbtBlock)
                        newBaseName.append(TString("[") + String(i) + "]");
                    TList<TIntermBinary*>::const_iterator nextDeref = deref;
                    ++nextDeref;
                    blowUpActiveAggregate(*terminalType, newBaseName, derefs, nextDeref, offset, blockIndex, arraySize,
                                          topLevelArraySize, topLevelArrayStride, baseStorage, active);

                    if (offset >= 0)
                        offset += stride;
                }

                // it was all completed in the recursive calls above
                return;
            }
            case EOpIndexDirect: {
                int stride = getArrayStride(baseType, visitNode->getLeft()->getType());

                index = visitNode->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();
                if (terminalType->getBasicType() == EbtBlock) {}
                else if (strictArraySuffix && blockParent)
                    name.append(TString("[0]"));
                else if (strictArraySuffix || baseType.getBasicType() != EbtBlock) {
                    name.append(TString("[") + String(index) + "]");

                    if (offset >= 0)
                        offset += stride * index;
                }

                if (topLevelArrayStride == 0)
                    topLevelArrayStride = stride;

                // expand top-level arrays in blocks with [0] suffix
                if (topLevelArrayStride != 0 && visitNode->getLeft()->getType().isArray()) {
                    blockParent = false;
                }
                break;
            }
            case EOpIndexDirectStruct:
                index = visitNode->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();
                if (offset >= 0)
                    offset += intermediate.getOffset(visitNode->getLeft()->getType(), index);
                if (name.size() > 0)
                    name.append(".");
                name.append((*visitNode->getLeft()->getType().getStruct())[index].type->getFieldName());

                // expand non top-level arrays with [x] suffix
                if (visitNode->getLeft()->getType().getBasicType() != EbtBlock && terminalType->isArray())
                {
                    blockParent = false;
                }
                break;
            default:
                break;
            }
        }

        // if the terminalType is still too coarse a granularity, this is still an aggregate to expand, expand it...
        if (! isReflectionGranularity(*terminalType)) {
            // the base offset of this node, that children are relative to
            int baseOffset = offset;

            if (terminalType->isArray()) {
                // Visit all the indices of this array, and for each one,
                // fully explode the remaining aggregate to dereference

                int stride = 0;
                if (offset >= 0)
                    stride = getArrayStride(baseType, *terminalType);

                int arrayIterateSize = std::max(terminalType->getOuterArraySize(), 1);

                // for top-level arrays in blocks, only expand [0] to avoid explosion of items
                if ((strictArraySuffix && blockParent) ||
                    ((topLevelArraySize == arrayIterateSize) && (topLevelArrayStride == 0))) {
                    arrayIterateSize = 1;
                }

                if (topLevelArrayStride == 0)
                    topLevelArrayStride = stride;

                for (int i = 0; i < arrayIterateSize; ++i) {
                    TString newBaseName = name;
                    if (terminalType->getBasicType() != EbtBlock)
                        newBaseName.append(TString("[") + String(i) + "]");
                    TType derefType(*terminalType, 0);
                    if (offset >= 0)
                        offset = baseOffset + stride * i;

                    blowUpActiveAggregate(derefType, newBaseName, derefs, derefs.end(), offset, blockIndex, 0,
                                          topLevelArraySize, topLevelArrayStride, baseStorage, active);
                }
            } else {
                // Visit all members of this aggregate, and for each one,
                // fully explode the remaining aggregate to dereference
                const TTypeList& typeList = *terminalType->getStruct();

                TVector<int> memberOffsets;

                if (baseOffset >= 0) {
                    memberOffsets.resize(typeList.size());
                    getOffsets(*terminalType, memberOffsets);
                }

                for (int i = 0; i < (int)typeList.size(); ++i) {
                    TString newBaseName = name;
                    if (newBaseName.size() > 0)
                        newBaseName.append(".");
                    newBaseName.append(typeList[i].type->getFieldName());
                    TType derefType(*terminalType, i);
                    if (offset >= 0)
                        offset = baseOffset + memberOffsets[i];

                    int arrayStride = topLevelArrayStride;
                    if (terminalType->getBasicType() == EbtBlock && terminalType->getQualifier().storage == EvqBuffer &&
                        derefType.isArray()) {
                        arrayStride = getArrayStride(baseType, derefType);
                    }

                    if (topLevelArraySize == -1 && arrayStride == 0 && blockParent)
                        topLevelArraySize = 1;

                    if (strictArraySuffix && blockParent) {
                        // if this member is an array, store the top-level array stride but start the explosion from
                        // the inner struct type.
                        if (derefType.isArray() && derefType.isStruct()) {
                            newBaseName.append("[0]");
                            auto dimSize = derefType.isUnsizedArray() ? 0 : derefType.getArraySizes()->getDimSize(0);
                            blowUpActiveAggregate(TType(derefType, 0), newBaseName, derefs, derefs.end(), memberOffsets[i],
                                blockIndex, 0, dimSize, arrayStride, terminalType->getQualifier().storage, false);
                        }
                        else if (derefType.isArray()) {
                            auto dimSize = derefType.isUnsizedArray() ? 0 : derefType.getArraySizes()->getDimSize(0);
                            blowUpActiveAggregate(derefType, newBaseName, derefs, derefs.end(), memberOffsets[i], blockIndex,
                                0, dimSize, 0, terminalType->getQualifier().storage, false);
                        }
                        else {
                            blowUpActiveAggregate(derefType, newBaseName, derefs, derefs.end(), memberOffsets[i], blockIndex,
                                0, 1, 0, terminalType->getQualifier().storage, false);
                        }
                    } else {
                        blowUpActiveAggregate(derefType, newBaseName, derefs, derefs.end(), offset, blockIndex, 0,
                                              topLevelArraySize, arrayStride, baseStorage, active);
                    }
                }
            }

            // it was all completed in the recursive calls above
            return;
        }

        if ((reflection.options & EShReflectionBasicArraySuffix) && terminalType->isArray()) {
            name.append(TString("[0]"));
        }

        // Finally, add a full string to the reflection database, and update the array size if necessary.
        // If the dereferenced entity to record is an array, compute the size and update the maximum size.

        // there might not be a final array dereference, it could have been copied as an array object
        if (arraySize == 0)
            arraySize = mapToGlArraySize(*terminalType);

        TReflection::TMapIndexToReflection& variables = reflection.GetVariableMapForStorage(baseStorage);

        TReflection::TNameToIndex::const_iterator it = reflection.nameToIndex.find(name.c_str());
        if (it == reflection.nameToIndex.end()) {
            int uniformIndex = (int)variables.size();
            reflection.nameToIndex[name.c_str()] = uniformIndex;
            variables.push_back(TObjectReflection(name.c_str(), *terminalType, offset, mapToGlType(*terminalType),
                                                  arraySize, blockIndex));
            if (terminalType->isArray()) {
                variables.back().arrayStride = getArrayStride(baseType, *terminalType);
                if (topLevelArrayStride == 0)
                    topLevelArrayStride = variables.back().arrayStride;
            }

            if ((reflection.options & EShReflectionSeparateBuffers) && terminalType->isAtomic())
                reflection.atomicCounterUniformIndices.push_back(uniformIndex);

            variables.back().topLevelArraySize = topLevelArraySize;
            variables.back().topLevelArrayStride = topLevelArrayStride;

            if ((reflection.options & EShReflectionAllBlockVariables) && active) {
                EShLanguageMask& stages = variables.back().stages;
                stages = static_cast<EShLanguageMask>(stages | 1 << intermediate.getStage());
            }
        } else {
            if (arraySize > 1) {
                int& reflectedArraySize = variables[it->second].size;
                reflectedArraySize = std::max(arraySize, reflectedArraySize);
            }

            if ((reflection.options & EShReflectionAllBlockVariables) && active) {
              EShLanguageMask& stages = variables[it->second].stages;
              stages = static_cast<EShLanguageMask>(stages | 1 << intermediate.getStage());
            }
        }
    }

    // similar to blowUpActiveAggregate, but with simpler rules and no dereferences to follow.
    void blowUpIOAggregate(bool input, const TString &baseName, const TType &type)
    {
        TString name = baseName;

        // if the type is still too coarse a granularity, this is still an aggregate to expand, expand it...
        if (! isReflectionGranularity(type)) {
            if (type.isArray()) {
                // Visit all the indices of this array, and for each one,
                // fully explode the remaining aggregate to dereference
                for (int i = 0; i < std::max(type.getOuterArraySize(), 1); ++i) {
                    TString newBaseName = name;
                    newBaseName.append(TString("[") + String(i) + "]");
                    TType derefType(type, 0);

                    blowUpIOAggregate(input, newBaseName, derefType);
                }
            } else {
                // Visit all members of this aggregate, and for each one,
                // fully explode the remaining aggregate to dereference
                const TTypeList& typeList = *type.getStruct();

                for (int i = 0; i < (int)typeList.size(); ++i) {
                    TString newBaseName = name;
                    if (newBaseName.size() > 0)
                        newBaseName.append(".");
                    newBaseName.append(typeList[i].type->getFieldName());
                    TType derefType(type, i);

                    blowUpIOAggregate(input, newBaseName, derefType);
                }
            }

            // it was all completed in the recursive calls above
            return;
        }

        if ((reflection.options & EShReflectionBasicArraySuffix) && type.isArray()) {
            name.append(TString("[0]"));
        }

        TReflection::TMapIndexToReflection &ioItems =
            input ? reflection.indexToPipeInput : reflection.indexToPipeOutput;

        std::string namespacedName = input ? "in " : "out ";
        namespacedName += name.c_str();

        TReflection::TNameToIndex::const_iterator it = reflection.nameToIndex.find(namespacedName);
        if (it == reflection.nameToIndex.end()) {
            reflection.nameToIndex[namespacedName] = (int)ioItems.size();
            ioItems.push_back(
                TObjectReflection(name.c_str(), type, 0, mapToGlType(type), mapToGlArraySize(type), 0));

            EShLanguageMask& stages = ioItems.back().stages;
            stages = static_cast<EShLanguageMask>(stages | 1 << intermediate.getStage());
        } else {
            EShLanguageMask& stages = ioItems[it->second].stages;
            stages = static_cast<EShLanguageMask>(stages | 1 << intermediate.getStage());
        }
    }

    // Add a uniform dereference where blocks/struct/arrays are involved in the access.
    // Handles the situation where the left node is at the correct or too coarse a
    // granularity for reflection.  (That is, further dereferences up the tree will be
    // skipped.) Earlier dereferences, down the tree, will be handled
    // at the same time, and logged to prevent reprocessing as the tree is traversed.
    //
    // Note: Other things like the following must be caught elsewhere:
    //  - a simple non-array, non-struct variable (no dereference even conceivable)
    //  - an aggregrate consumed en masse, without a dereference
    //
    // So, this code is for cases like
    //   - a struct/block dereferencing a member (whether the member is array or not)
    //   - an array of struct
    //   - structs/arrays containing the above
    //
    void addDereferencedUniform(TIntermBinary* topNode)
    {
        // See if too fine-grained to process (wait to get further down the tree)
        const TType& leftType = topNode->getLeft()->getType();
        if ((leftType.isVector() || leftType.isMatrix()) && ! leftType.isArray())
            return;

        // We have an array or structure or block dereference, see if it's a uniform
        // based dereference (if not, skip it).
        TIntermSymbol* base = findBase(topNode);
        if (! base || ! base->getQualifier().isUniformOrBuffer())
            return;

        // See if we've already processed this (e.g., in the middle of something
        // we did earlier), and if so skip it
        if (processedDerefs.find(topNode) != processedDerefs.end())
            return;

        // Process this uniform dereference

        int offset = -1;
        int blockIndex = -1;
        bool anonymous = false;

        // See if we need to record the block itself
        bool block = base->getBasicType() == EbtBlock;
        if (block) {
            offset = 0;
            anonymous = IsAnonymous(base->getName());

            const TString& blockName = base->getType().getTypeName();
            TString baseName;

            if (! anonymous)
                baseName = blockName;

            blockIndex = addBlockName(blockName, base->getType(), intermediate.getBlockSize(base->getType()));

            if (reflection.options & EShReflectionAllBlockVariables) {
                // Use a degenerate (empty) set of dereferences to immediately put as at the end of
                // the dereference change expected by blowUpActiveAggregate.
                TList<TIntermBinary*> derefs;

                // otherwise - if we're not using strict array suffix rules, or this isn't a block so we are
                // expanding root arrays anyway, just start the iteration from the base block type.
                blowUpActiveAggregate(base->getType(), baseName, derefs, derefs.end(), 0, blockIndex, 0, -1, 0,
                                          base->getQualifier().storage, false);
            }
        }

        // Process the dereference chain, backward, accumulating the pieces for later forward traversal.
        // If the topNode is a reflection-granularity-array dereference, don't include that last dereference.
        TList<TIntermBinary*> derefs;
        for (TIntermBinary* visitNode = topNode; visitNode; visitNode = visitNode->getLeft()->getAsBinaryNode()) {
            if (isReflectionGranularity(visitNode->getLeft()->getType()))
                continue;

            derefs.push_front(visitNode);
            processedDerefs.insert(visitNode);
        }
        processedDerefs.insert(base);

        // See if we have a specific array size to stick to while enumerating the explosion of the aggregate
        int arraySize = 0;
        if (isReflectionGranularity(topNode->getLeft()->getType()) && topNode->getLeft()->isArray()) {
            if (topNode->getOp() == EOpIndexDirect)
                arraySize = topNode->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst() + 1;
        }

        // Put the dereference chain together, forward
        TString baseName;
        if (! anonymous) {
            if (block)
                baseName = base->getType().getTypeName();
            else
                baseName = base->getName();
        }
        blowUpActiveAggregate(base->getType(), baseName, derefs, derefs.begin(), offset, blockIndex, arraySize, -1, 0,
                              base->getQualifier().storage, true);
    }

    int addBlockName(const TString& name, const TType& type, int size)
    {
        int blockIndex = 0;
        if (type.isArray()) {
            TType derefType(type, 0);
            for (int e = 0; e < type.getOuterArraySize(); ++e) {
                int memberBlockIndex = addBlockName(name + "[" + String(e) + "]", derefType, size);
                if (e == 0)
                    blockIndex = memberBlockIndex;
            }
        } else {
            TReflection::TMapIndexToReflection& blocks = reflection.GetBlockMapForStorage(type.getQualifier().storage);

            TReflection::TNameToIndex::const_iterator it = reflection.nameToIndex.find(name.c_str());
            if (reflection.nameToIndex.find(name.c_str()) == reflection.nameToIndex.end()) {
                blockIndex = (int)blocks.size();
                reflection.nameToIndex[name.c_str()] = blockIndex;
                blocks.push_back(TObjectReflection(name.c_str(), type, -1, -1, size, blockIndex));

                blocks.back().numMembers = countAggregateMembers(type);

                if (updateStageMasks) {
                    EShLanguageMask& stages = blocks.back().stages;
                    stages = static_cast<EShLanguageMask>(stages | 1 << intermediate.getStage());
                }
            }
            else {
                blockIndex = it->second;
                if (updateStageMasks) {
                    EShLanguageMask& stages = blocks[blockIndex].stages;
                    stages = static_cast<EShLanguageMask>(stages | 1 << intermediate.getStage());
                }
            }
        }

        return blockIndex;
    }

    // Are we at a level in a dereference chain at which individual active uniform queries are made?
    bool isReflectionGranularity(const TType& type)
    {
        return type.getBasicType() != EbtBlock && type.getBasicType() != EbtStruct && !type.isArrayOfArrays();
    }

    // For a binary operation indexing into an aggregate, chase down the base of the aggregate.
    // Return 0 if the topology does not fit this situation.
    TIntermSymbol* findBase(const TIntermBinary* node)
    {
        TIntermSymbol *base = node->getLeft()->getAsSymbolNode();
        if (base)
            return base;
        TIntermBinary* left = node->getLeft()->getAsBinaryNode();
        if (! left)
            return nullptr;

        return findBase(left);
    }

    //
    // Translate a glslang sampler type into the GL API #define number.
    //
    int mapSamplerToGlType(TSampler sampler)
    {
        if (! sampler.image) {
            // a sampler...
            switch (sampler.type) {
            case EbtFloat:
                switch ((int)sampler.dim) {
                case Esd1D:
                    switch ((int)sampler.shadow) {
                    case false: return sampler.arrayed ? GL_SAMPLER_1D_ARRAY : GL_SAMPLER_1D;
                    case true:  return sampler.arrayed ? GL_SAMPLER_1D_ARRAY_SHADOW : GL_SAMPLER_1D_SHADOW;
                    }
                case Esd2D:
                    switch ((int)sampler.ms) {
                    case false:
                        switch ((int)sampler.shadow) {
                        case false: return sampler.arrayed ? GL_SAMPLER_2D_ARRAY : GL_SAMPLER_2D;
                        case true:  return sampler.arrayed ? GL_SAMPLER_2D_ARRAY_SHADOW : GL_SAMPLER_2D_SHADOW;
                        }
                    case true:      return sampler.arrayed ? GL_SAMPLER_2D_MULTISAMPLE_ARRAY : GL_SAMPLER_2D_MULTISAMPLE;
                    }
                case Esd3D:
                    return GL_SAMPLER_3D;
                case EsdCube:
                    switch ((int)sampler.shadow) {
                    case false: return sampler.arrayed ? GL_SAMPLER_CUBE_MAP_ARRAY : GL_SAMPLER_CUBE;
                    case true:  return sampler.arrayed ? GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW : GL_SAMPLER_CUBE_SHADOW;
                    }
                case EsdRect:
                    return sampler.shadow ? GL_SAMPLER_2D_RECT_SHADOW : GL_SAMPLER_2D_RECT;
                case EsdBuffer:
                    return GL_SAMPLER_BUFFER;
                }
            case EbtFloat16:
                switch ((int)sampler.dim) {
                case Esd1D:
                    switch ((int)sampler.shadow) {
                    case false: return sampler.arrayed ? GL_FLOAT16_SAMPLER_1D_ARRAY_AMD : GL_FLOAT16_SAMPLER_1D_AMD;
                    case true:  return sampler.arrayed ? GL_FLOAT16_SAMPLER_1D_ARRAY_SHADOW_AMD : GL_FLOAT16_SAMPLER_1D_SHADOW_AMD;
                    }
                case Esd2D:
                    switch ((int)sampler.ms) {
                    case false:
                        switch ((int)sampler.shadow) {
                        case false: return sampler.arrayed ? GL_FLOAT16_SAMPLER_2D_ARRAY_AMD : GL_FLOAT16_SAMPLER_2D_AMD;
                        case true:  return sampler.arrayed ? GL_FLOAT16_SAMPLER_2D_ARRAY_SHADOW_AMD : GL_FLOAT16_SAMPLER_2D_SHADOW_AMD;
                        }
                    case true:      return sampler.arrayed ? GL_FLOAT16_SAMPLER_2D_MULTISAMPLE_ARRAY_AMD : GL_FLOAT16_SAMPLER_2D_MULTISAMPLE_AMD;
                    }
                case Esd3D:
                    return GL_FLOAT16_SAMPLER_3D_AMD;
                case EsdCube:
                    switch ((int)sampler.shadow) {
                    case false: return sampler.arrayed ? GL_FLOAT16_SAMPLER_CUBE_MAP_ARRAY_AMD : GL_FLOAT16_SAMPLER_CUBE_AMD;
                    case true:  return sampler.arrayed ? GL_FLOAT16_SAMPLER_CUBE_MAP_ARRAY_SHADOW_AMD : GL_FLOAT16_SAMPLER_CUBE_SHADOW_AMD;
                    }
                case EsdRect:
                    return sampler.shadow ? GL_FLOAT16_SAMPLER_2D_RECT_SHADOW_AMD : GL_FLOAT16_SAMPLER_2D_RECT_AMD;
                case EsdBuffer:
                    return GL_FLOAT16_SAMPLER_BUFFER_AMD;
                }
            case EbtInt:
                switch ((int)sampler.dim) {
                case Esd1D:
                    return sampler.arrayed ? GL_INT_SAMPLER_1D_ARRAY : GL_INT_SAMPLER_1D;
                case Esd2D:
                    switch ((int)sampler.ms) {
                    case false:  return sampler.arrayed ? GL_INT_SAMPLER_2D_ARRAY : GL_INT_SAMPLER_2D;
                    case true:   return sampler.arrayed ? GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY
                                                        : GL_INT_SAMPLER_2D_MULTISAMPLE;
                    }
                case Esd3D:
                    return GL_INT_SAMPLER_3D;
                case EsdCube:
                    return sampler.arrayed ? GL_INT_SAMPLER_CUBE_MAP_ARRAY : GL_INT_SAMPLER_CUBE;
                case EsdRect:
                    return GL_INT_SAMPLER_2D_RECT;
                case EsdBuffer:
                    return GL_INT_SAMPLER_BUFFER;
                }
            case EbtUint:
                switch ((int)sampler.dim) {
                case Esd1D:
                    return sampler.arrayed ? GL_UNSIGNED_INT_SAMPLER_1D_ARRAY : GL_UNSIGNED_INT_SAMPLER_1D;
                case Esd2D:
                    switch ((int)sampler.ms) {
                    case false:  return sampler.arrayed ? GL_UNSIGNED_INT_SAMPLER_2D_ARRAY : GL_UNSIGNED_INT_SAMPLER_2D;
                    case true:   return sampler.arrayed ? GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY
                                                        : GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE;
                    }
                case Esd3D:
                    return GL_UNSIGNED_INT_SAMPLER_3D;
                case EsdCube:
                    return sampler.arrayed ? GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY : GL_UNSIGNED_INT_SAMPLER_CUBE;
                case EsdRect:
                    return GL_UNSIGNED_INT_SAMPLER_2D_RECT;
                case EsdBuffer:
                    return GL_UNSIGNED_INT_SAMPLER_BUFFER;
                }
            default:
                return 0;
            }
        } else {
            // an image...
            switch (sampler.type) {
            case EbtFloat:
                switch ((int)sampler.dim) {
                case Esd1D:
                    return sampler.arrayed ? GL_IMAGE_1D_ARRAY : GL_IMAGE_1D;
                case Esd2D:
                    switch ((int)sampler.ms) {
                    case false:     return sampler.arrayed ? GL_IMAGE_2D_ARRAY : GL_IMAGE_2D;
                    case true:      return sampler.arrayed ? GL_IMAGE_2D_MULTISAMPLE_ARRAY : GL_IMAGE_2D_MULTISAMPLE;
                    }
                case Esd3D:
                    return GL_IMAGE_3D;
                case EsdCube:
                    return sampler.arrayed ? GL_IMAGE_CUBE_MAP_ARRAY : GL_IMAGE_CUBE;
                case EsdRect:
                    return GL_IMAGE_2D_RECT;
                case EsdBuffer:
                    return GL_IMAGE_BUFFER;
                }
            case EbtFloat16:
                switch ((int)sampler.dim) {
                case Esd1D:
                    return sampler.arrayed ? GL_FLOAT16_IMAGE_1D_ARRAY_AMD : GL_FLOAT16_IMAGE_1D_AMD;
                case Esd2D:
                    switch ((int)sampler.ms) {
                    case false:     return sampler.arrayed ? GL_FLOAT16_IMAGE_2D_ARRAY_AMD : GL_FLOAT16_IMAGE_2D_AMD;
                    case true:      return sampler.arrayed ? GL_FLOAT16_IMAGE_2D_MULTISAMPLE_ARRAY_AMD : GL_FLOAT16_IMAGE_2D_MULTISAMPLE_AMD;
                    }
                case Esd3D:
                    return GL_FLOAT16_IMAGE_3D_AMD;
                case EsdCube:
                    return sampler.arrayed ? GL_FLOAT16_IMAGE_CUBE_MAP_ARRAY_AMD : GL_FLOAT16_IMAGE_CUBE_AMD;
                case EsdRect:
                    return GL_FLOAT16_IMAGE_2D_RECT_AMD;
                case EsdBuffer:
                    return GL_FLOAT16_IMAGE_BUFFER_AMD;
                }
            case EbtInt:
                switch ((int)sampler.dim) {
                case Esd1D:
                    return sampler.arrayed ? GL_INT_IMAGE_1D_ARRAY : GL_INT_IMAGE_1D;
                case Esd2D:
                    switch ((int)sampler.ms) {
                    case false:  return sampler.arrayed ? GL_INT_IMAGE_2D_ARRAY : GL_INT_IMAGE_2D;
                    case true:   return sampler.arrayed ? GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY : GL_INT_IMAGE_2D_MULTISAMPLE;
                    }
                case Esd3D:
                    return GL_INT_IMAGE_3D;
                case EsdCube:
                    return sampler.arrayed ? GL_INT_IMAGE_CUBE_MAP_ARRAY : GL_INT_IMAGE_CUBE;
                case EsdRect:
                    return GL_INT_IMAGE_2D_RECT;
                case EsdBuffer:
                    return GL_INT_IMAGE_BUFFER;
                }
            case EbtUint:
                switch ((int)sampler.dim) {
                case Esd1D:
                    return sampler.arrayed ? GL_UNSIGNED_INT_IMAGE_1D_ARRAY : GL_UNSIGNED_INT_IMAGE_1D;
                case Esd2D:
                    switch ((int)sampler.ms) {
                    case false:  return sampler.arrayed ? GL_UNSIGNED_INT_IMAGE_2D_ARRAY : GL_UNSIGNED_INT_IMAGE_2D;
                    case true:   return sampler.arrayed ? GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY
                                                        : GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE;
                    }
                case Esd3D:
                    return GL_UNSIGNED_INT_IMAGE_3D;
                case EsdCube:
                    return sampler.arrayed ? GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY : GL_UNSIGNED_INT_IMAGE_CUBE;
                case EsdRect:
                    return GL_UNSIGNED_INT_IMAGE_2D_RECT;
                case EsdBuffer:
                    return GL_UNSIGNED_INT_IMAGE_BUFFER;
                }
            default:
                return 0;
            }
        }
    }

    //
    // Translate a glslang type into the GL API #define number.
    // Ignores arrayness.
    //
    int mapToGlType(const TType& type)
    {
        switch (type.getBasicType()) {
        case EbtSampler:
            return mapSamplerToGlType(type.getSampler());
        case EbtStruct:
        case EbtBlock:
        case EbtVoid:
            return 0;
        default:
            break;
        }

        if (type.isVector()) {
            int offset = type.getVectorSize() - 2;
            switch (type.getBasicType()) {
            case EbtFloat:      return GL_FLOAT_VEC2                  + offset;
            case EbtDouble:     return GL_DOUBLE_VEC2                 + offset;
            case EbtFloat16:    return GL_FLOAT16_VEC2_NV             + offset;
            case EbtInt:        return GL_INT_VEC2                    + offset;
            case EbtUint:       return GL_UNSIGNED_INT_VEC2           + offset;
            case EbtInt64:      return GL_INT64_VEC2_ARB              + offset;
            case EbtUint64:     return GL_UNSIGNED_INT64_VEC2_ARB     + offset;
            case EbtBool:       return GL_BOOL_VEC2                   + offset;
            case EbtAtomicUint: return GL_UNSIGNED_INT_ATOMIC_COUNTER + offset;
            default:            return 0;
            }
        }
        if (type.isMatrix()) {
            switch (type.getBasicType()) {
            case EbtFloat:
                switch (type.getMatrixCols()) {
                case 2:
                    switch (type.getMatrixRows()) {
                    case 2:    return GL_FLOAT_MAT2;
                    case 3:    return GL_FLOAT_MAT2x3;
                    case 4:    return GL_FLOAT_MAT2x4;
                    default:   return 0;
                    }
                case 3:
                    switch (type.getMatrixRows()) {
                    case 2:    return GL_FLOAT_MAT3x2;
                    case 3:    return GL_FLOAT_MAT3;
                    case 4:    return GL_FLOAT_MAT3x4;
                    default:   return 0;
                    }
                case 4:
                    switch (type.getMatrixRows()) {
                    case 2:    return GL_FLOAT_MAT4x2;
                    case 3:    return GL_FLOAT_MAT4x3;
                    case 4:    return GL_FLOAT_MAT4;
                    default:   return 0;
                    }
                }
            case EbtDouble:
                switch (type.getMatrixCols()) {
                case 2:
                    switch (type.getMatrixRows()) {
                    case 2:    return GL_DOUBLE_MAT2;
                    case 3:    return GL_DOUBLE_MAT2x3;
                    case 4:    return GL_DOUBLE_MAT2x4;
                    default:   return 0;
                    }
                case 3:
                    switch (type.getMatrixRows()) {
                    case 2:    return GL_DOUBLE_MAT3x2;
                    case 3:    return GL_DOUBLE_MAT3;
                    case 4:    return GL_DOUBLE_MAT3x4;
                    default:   return 0;
                    }
                case 4:
                    switch (type.getMatrixRows()) {
                    case 2:    return GL_DOUBLE_MAT4x2;
                    case 3:    return GL_DOUBLE_MAT4x3;
                    case 4:    return GL_DOUBLE_MAT4;
                    default:   return 0;
                    }
                }
            case EbtFloat16:
                switch (type.getMatrixCols()) {
                case 2:
                    switch (type.getMatrixRows()) {
                    case 2:    return GL_FLOAT16_MAT2_AMD;
                    case 3:    return GL_FLOAT16_MAT2x3_AMD;
                    case 4:    return GL_FLOAT16_MAT2x4_AMD;
                    default:   return 0;
                    }
                case 3:
                    switch (type.getMatrixRows()) {
                    case 2:    return GL_FLOAT16_MAT3x2_AMD;
                    case 3:    return GL_FLOAT16_MAT3_AMD;
                    case 4:    return GL_FLOAT16_MAT3x4_AMD;
                    default:   return 0;
                    }
                case 4:
                    switch (type.getMatrixRows()) {
                    case 2:    return GL_FLOAT16_MAT4x2_AMD;
                    case 3:    return GL_FLOAT16_MAT4x3_AMD;
                    case 4:    return GL_FLOAT16_MAT4_AMD;
                    default:   return 0;
                    }
                }
            default:
                return 0;
            }
        }
        if (type.getVectorSize() == 1) {
            switch (type.getBasicType()) {
            case EbtFloat:      return GL_FLOAT;
            case EbtDouble:     return GL_DOUBLE;
            case EbtFloat16:    return GL_FLOAT16_NV;
            case EbtInt:        return GL_INT;
            case EbtUint:       return GL_UNSIGNED_INT;
            case EbtInt64:      return GL_INT64_ARB;
            case EbtUint64:     return GL_UNSIGNED_INT64_ARB;
            case EbtBool:       return GL_BOOL;
            case EbtAtomicUint: return GL_UNSIGNED_INT_ATOMIC_COUNTER;
            default:            return 0;
            }
        }

        return 0;
    }

    int mapToGlArraySize(const TType& type)
    {
        return type.isArray() ? type.getOuterArraySize() : 1;
    }

    const TIntermediate& intermediate;
    TReflection& reflection;
    std::set<const TIntermNode*> processedDerefs;
    bool updateStageMasks;

protected:
    TReflectionTraverser(TReflectionTraverser&);
    TReflectionTraverser& operator=(TReflectionTraverser&);
};

//
// Implement the traversal functions of interest.
//

// To catch dereferenced aggregates that must be reflected.
// This catches them at the highest level possible in the tree.
bool TReflectionTraverser::visitBinary(TVisit /* visit */, TIntermBinary* node)
{
    switch (node->getOp()) {
    case EOpIndexDirect:
    case EOpIndexIndirect:
    case EOpIndexDirectStruct:
        addDereferencedUniform(node);
        break;
    default:
        break;
    }

    // still need to visit everything below, which could contain sub-expressions
    // containing different uniforms
    return true;
}

// To reflect non-dereferenced objects.
void TReflectionTraverser::visitSymbol(TIntermSymbol* base)
{
    if (base->getQualifier().storage == EvqUniform) {
        if (base->getBasicType() == EbtBlock) {
            if (reflection.options & EShReflectionSharedStd140UBO) {
                addUniform(*base);
            }
        } else {
            addUniform(*base);
        }
    }

    // #TODO add std140/layout active rules for ssbo, same with ubo.
    // Storage buffer blocks will be collected and expanding in this part.
    if((reflection.options & EShReflectionSharedStd140SSBO) &&
       (base->getQualifier().storage == EvqBuffer && base->getBasicType() == EbtBlock &&
        (base->getQualifier().layoutPacking == ElpStd140 || base->getQualifier().layoutPacking == ElpShared)))
        addUniform(*base);

    if ((intermediate.getStage() == reflection.firstStage && base->getQualifier().isPipeInput()) ||
        (intermediate.getStage() == reflection.lastStage && base->getQualifier().isPipeOutput()))
        addPipeIOVariable(*base);
}

//
// Implement TObjectReflection methods.
//

TObjectReflection::TObjectReflection(const std::string &pName, const TType &pType, int pOffset, int pGLDefineType,
                                     int pSize, int pIndex)
    : name(pName), offset(pOffset), glDefineType(pGLDefineType), size(pSize), index(pIndex), counterIndex(-1),
      numMembers(-1), arrayStride(0), topLevelArrayStride(0), stages(EShLanguageMask(0)), type(pType.clone())
{
}

int TObjectReflection::getBinding() const
{
    if (type == nullptr || !type->getQualifier().hasBinding())
        return -1;
    return type->getQualifier().layoutBinding;
}

void TObjectReflection::dump() const
{
    printf("%s: offset %d, type %x, size %d, index %d, binding %d, stages %d", name.c_str(), offset, glDefineType, size,
           index, getBinding(), stages);

    if (counterIndex != -1)
        printf(", counter %d", counterIndex);

    if (numMembers != -1)
        printf(", numMembers %d", numMembers);

    if (arrayStride != 0)
        printf(", arrayStride %d", arrayStride);

    if (topLevelArrayStride != 0)
        printf(", topLevelArrayStride %d", topLevelArrayStride);

    printf("\n");
}

//
// Implement TReflection methods.
//

// Track any required attribute reflection, such as compute shader numthreads.
//
void TReflection::buildAttributeReflection(EShLanguage stage, const TIntermediate& intermediate)
{
    if (stage == EShLangCompute) {
        // Remember thread dimensions
        for (int dim=0; dim<3; ++dim)
            localSize[dim] = intermediate.getLocalSize(dim);
    }
}

// build counter block index associations for buffers
void TReflection::buildCounterIndices(const TIntermediate& intermediate)
{
#ifdef ENABLE_HLSL
    // search for ones that have counters
    for (int i = 0; i < int(indexToUniformBlock.size()); ++i) {
        const TString counterName(intermediate.addCounterBufferName(indexToUniformBlock[i].name).c_str());
        const int index = getIndex(counterName);

        if (index >= 0)
            indexToUniformBlock[i].counterIndex = index;
    }
#else
    (void)intermediate;
#endif
}

// build Shader Stages mask for all uniforms
void TReflection::buildUniformStageMask(const TIntermediate& intermediate)
{
    if (options & EShReflectionAllBlockVariables)
        return;

    for (int i = 0; i < int(indexToUniform.size()); ++i) {
        indexToUniform[i].stages = static_cast<EShLanguageMask>(indexToUniform[i].stages | 1 << intermediate.getStage());
    }

    for (int i = 0; i < int(indexToBufferVariable.size()); ++i) {
        indexToBufferVariable[i].stages =
            static_cast<EShLanguageMask>(indexToBufferVariable[i].stages | 1 << intermediate.getStage());
    }
}

// Merge live symbols from 'intermediate' into the existing reflection database.
//
// Returns false if the input is too malformed to do this.
bool TReflection::addStage(EShLanguage stage, const TIntermediate& intermediate)
{
    if (intermediate.getTreeRoot() == nullptr ||
        intermediate.getNumEntryPoints() != 1 ||
        intermediate.isRecursive())
        return false;

    buildAttributeReflection(stage, intermediate);

    TReflectionTraverser it(intermediate, *this);

    for (auto& sequnence : intermediate.getTreeRoot()->getAsAggregate()->getSequence()) {
        if (sequnence->getAsAggregate() != nullptr) {
            if (sequnence->getAsAggregate()->getOp() == glslang::EOpLinkerObjects) {
                it.updateStageMasks = false;
                TIntermAggregate* linkerObjects = sequnence->getAsAggregate();
                for (auto& sequnence : linkerObjects->getSequence()) {
                    auto pNode = sequnence->getAsSymbolNode();
                    if (pNode != nullptr) {
                        if ((pNode->getQualifier().storage == EvqUniform &&
                            (options & EShReflectionSharedStd140UBO)) ||
                           (pNode->getQualifier().storage == EvqBuffer &&
                            (options & EShReflectionSharedStd140SSBO))) {
                            // collect std140 and shared uniform block form AST
                            if ((pNode->getBasicType() == EbtBlock) &&
                                ((pNode->getQualifier().layoutPacking == ElpStd140) ||
                                 (pNode->getQualifier().layoutPacking == ElpShared))) {
                                   pNode->traverse(&it);
                            }
                        }
                        else if ((options & EShReflectionAllIOVariables) &&
                            (pNode->getQualifier().isPipeInput() || pNode->getQualifier().isPipeOutput()))
                        {
                            pNode->traverse(&it);
                        }
                    }
                }
            } else {
                // This traverser will travers all function in AST.
                // If we want reflect uncalled function, we need set linke message EShMsgKeepUncalled.
                // When EShMsgKeepUncalled been set to true, all function will be keep in AST, even it is a uncalled function.
                // This will keep some uniform variables in reflection, if those uniform variables is used in these uncalled function.
                //
                // If we just want reflect only live node, we can use a default link message or set EShMsgKeepUncalled false.
                // When linke message not been set EShMsgKeepUncalled, linker won't keep uncalled function in AST.
                // So, travers all function node can equivalent to travers live function.
                it.updateStageMasks = true;
                sequnence->getAsAggregate()->traverse(&it);
            }
        }
    }
    it.updateStageMasks = true;

    buildCounterIndices(intermediate);
    buildUniformStageMask(intermediate);

    return true;
}

void TReflection::dump()
{
    printf("Uniform reflection:\n");
    for (size_t i = 0; i < indexToUniform.size(); ++i)
        indexToUniform[i].dump();
    printf("\n");

    printf("Uniform block reflection:\n");
    for (size_t i = 0; i < indexToUniformBlock.size(); ++i)
        indexToUniformBlock[i].dump();
    printf("\n");

    printf("Buffer variable reflection:\n");
    for (size_t i = 0; i < indexToBufferVariable.size(); ++i)
      indexToBufferVariable[i].dump();
    printf("\n");

    printf("Buffer block reflection:\n");
    for (size_t i = 0; i < indexToBufferBlock.size(); ++i)
      indexToBufferBlock[i].dump();
    printf("\n");

    printf("Pipeline input reflection:\n");
    for (size_t i = 0; i < indexToPipeInput.size(); ++i)
        indexToPipeInput[i].dump();
    printf("\n");

    printf("Pipeline output reflection:\n");
    for (size_t i = 0; i < indexToPipeOutput.size(); ++i)
        indexToPipeOutput[i].dump();
    printf("\n");

    if (getLocalSize(0) > 1) {
        static const char* axis[] = { "X", "Y", "Z" };

        for (int dim=0; dim<3; ++dim)
            if (getLocalSize(dim) > 1)
                printf("Local size %s: %u\n", axis[dim], getLocalSize(dim));

        printf("\n");
    }

    // printf("Live names\n");
    // for (TNameToIndex::const_iterator it = nameToIndex.begin(); it != nameToIndex.end(); ++it)
    //    printf("%s: %d\n", it->first.c_str(), it->second);
    // printf("\n");
}

} // end namespace glslang

#endif // !GLSLANG_WEB


text:
A ruby interface to the [CityBikes API](http://api.citybik.es/v2/) v2.
 Returns data about bike-share networks and stations.
 Includes options to customize API requests.

[![Gem Version](https://badge.fury.io/rb/citybikes_api.svg)](https://badge.fury.io/rb/citybikes_api)

## Installation

Add `gem 'citybikes_api', '~> 2.0'` to Gemfile and run `bundle install`. Or install with:

```` sh
gem install citybikes_api
````

## Usage

### Requests

#### Networks Endpoint

List all bike-share networks.

```` rb
response = CitybikesApi.networks
puts response["networks"] #=> returns an Array of Hash objects
````

#### Network Endpoint

Find a bike-share network by its CityBikes identifier.

```` rb
network_id = "capital-bikeshare"
response = CitybikesApi.network(network_id)
puts response["network"] #=> returns a Hash object
````

### Request Options

Customize any network request by passing URL parameters.

```` rb
request_options = {:fields => "id,name,href"}
response = CitybikesApi.networks(request_options)
puts response["networks"] #=> returns an Array of Hash objects, each of which should only contain the requested fields/attributes
````

```` rb
network_id = "capital-bikeshare"
request_options = {:fields => "id,name,href"}
response = CitybikesApi.network(network_id, request_options)
puts response["network"] #=> returns a Hash object which should only contain the requested fields/attributes
````

See [CityBikes documentation](http://api.citybik.es/v2/#Syntax) for more info about field-filtering.

## Contributing

Browse existing [issues](https://github.com/data-creative/citybikes-api-ruby/issues) or create a new issue to communicate bugs, desired features, etc.

After forking the repo and pushing your changes, create a pull request referencing the applicable issue(s).

### Developing

After checking out the repo, run `bin/setup` to install dependencies.

### Testing

Run `rake rspec` or `bundle exec rspec spec/` to run the tests.

You can also run `bin/console` for an interactive prompt that will allow you to experiment.

### Releasing

To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).

## [License](LICENSE.txt)

redpajama_set_name: RedPajamaGithub


text:
package com.hironytic.moltonfdroid;

import java.io.File;
import java.util.Locale;

import android.annotation.TargetApi;
import android.app.Application;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Build;
import android.os.Environment;

/**
 * Moltonfアプリケーション
 */
public class MoltonfApplication extends Application {

    private static final String WORK_DIR_NAME_FORMAT = "Android/data/%s/files";

    /**
     * アプリケーションが作られたときに呼び出されます。
     */
    @Override
    public void onCreate() {
        super.onCreate();

        Moltonf moltonf = Moltonf.getInstance();
        String packageName = getPackageName();

        // バージョン文字列
        String versionString = "";
        try {
            PackageInfo packageInfo = getPackageManager().getPackageInfo(packageName, PackageManager.GET_META_DATA);
            versionString = packageInfo.versionName;
        } catch (NameNotFoundException ex) {
        }
        moltonf.setVersionString(versionString);

        // 作業ディレクトリ
        File workDir;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) {
            workDir = getWorkDirV8();
        } else {
            try {
                File sdcardDir = Environment.getExternalStorageDirectory();
                workDir = new File(sdcardDir, String.format(Locale.US, WORK_DIR_NAME_FORMAT, packageName));
                if (!workDir.exists()) {
                    if (sdcardDir.canWrite()) {
                        workDir.mkdirs();
                    } else {
                        workDir = null;
                    }
                }
            } catch (SecurityException ex) {
                workDir = null;
            }
        }
        moltonf.setWorkDir(workDir);
    }

    /**
     * MoltonfDroid アプリケーションの扱うファイルを格納しているディレクトリを返します。(API Level 8以上専用)
     * @return アプリケーションの扱うファイルを格納しているディレクトリ
     *          取得できなければ null を返します。
     */
    @TargetApi(8)
    private File getWorkDirV8() {
        return this.getExternalFilesDir(null);
    }

}


text:
static const int ddLogLevel = LOG_LEVEL_OFF;

@implementation DCSRMServer

- (id)init {
    self = [super init];
    if(self) {
        // Initalize our http server
        httpServer = [[HTTPServer alloc] init];

        // Tell server to use our custom MyHTTPConnection class.
        [httpServer setConnectionClass:[DCSRSpotifyConnection class]];
    }
    return self;
}

- (BOOL)start {
    // Tell the server to broadcast its presence via Bonjour.
    if([[DCPreferencesManager instance].preferences boolForKey:@"broadcastServer"]) {
        [httpServer setType:@"_reign._tcp."];
    } else {
        [httpServer setType:nil];
    }

    // Serve files from Music/Reign/Themes/Default our embedded Web folder
    NSString *webPath = [[DCPreferencesManager instance] webPath];
    DDLogVerbose(@"Setting document root: %@", webPath);
    [httpServer setDocumentRoot:webPath];

    // Launch on specific port
    if(![[DCPreferencesManager instance].preferences boolForKey:@"dynamicServerPort"]) {
        [httpServer setPort:[[DCPreferencesManager instance].preferences integerForKey:@"staticServerPort"]];
    } else {
        [httpServer setPort:0];
    }

    NSError *error;
    BOOL success = [httpServer start:&error];

    if(!success)
    {
        DDLogError(@"Error starting HTTP Server: %@", error);
    } else {

        // Broadcast on standard http bonjour service as well
        if([[DCPreferencesManager instance].preferences boolForKey:@"broadcastServer"]) {
            NSString *httpName = [[NSString alloc] initWithFormat:NSLocalizedString(@"Reign on %@", @"Displayed in the http Bonjour service name"), (__bridge NSString*)CSCopyMachineName()];
            netService = [[NSNetService alloc] initWithDomain:@"local." type:@"_http._tcp." name:httpName port:httpServer.port];
            [netService publish];
        }
    }
    return success;
}
- (void)stop {
    [httpServer stop];

    [netService stop];
    netService = nil;
}

- (BOOL)isRunning {
    return [httpServer isRunning];
}

- (uint16)port {
    return [httpServer listeningPort];
}
- (NSString *)name {
        return [httpServer name];
}

@end


text:
package com.jetbrains.python.codeInsight.regexp;

import com.intellij.lang.PsiParser;
import com.intellij.lexer.Lexer;
import com.intellij.openapi.project.Project;
import com.intellij.psi.FileViewProvider;
import com.intellij.psi.PsiFile;
import com.intellij.psi.tree.IFileElementType;
import org.intellij.lang.regexp.*;
import org.jetbrains.annotations.NotNull;

import java.util.EnumSet;

/**
 * @author yole
 */
public class PythonVerboseRegexpParserDefinition extends PythonRegexpParserDefinition {
  public static final IFileElementType VERBOSE_PYTHON_REGEXP_FILE = new IFileElementType("VERBOSE_PYTHON_REGEXP_FILE", PythonVerboseRegexpLanguage.INSTANCE);
  private final EnumSet<RegExpCapability> VERBOSE_CAPABILITIES;

  public PythonVerboseRegexpParserDefinition() {
    VERBOSE_CAPABILITIES = EnumSet.copyOf(CAPABILITIES);
    VERBOSE_CAPABILITIES.add(RegExpCapability.COMMENT_MODE);
  }

  @NotNull
  public Lexer createLexer(Project project) {
    return new RegExpLexer(VERBOSE_CAPABILITIES);
  }

  @Override
  public PsiParser createParser(Project project) {
    return new RegExpParser(VERBOSE_CAPABILITIES);
  }

  @Override
  public IFileElementType getFileNodeType() {
    return VERBOSE_PYTHON_REGEXP_FILE;
  }

  @Override
  public PsiFile createFile(FileViewProvider viewProvider) {
    return new RegExpFile(viewProvider, PythonVerboseRegexpLanguage.INSTANCE);
  }
}


text:
[![Build Status](https://travis-ci.org/harmandeol/moviesearch.svg?branch=master)](https://travis-ci.org/harmandeol/moviesearch) [Demo](https://omdbmovie.herokuapp.com)
# Introduction

A movie search app using [angular2 seed template](https://github.com/mgechev/angular2-seed). I used this template to showcase best practices.

[Omdbapi](http://omdbapi) allows to search by title and year. I have implemented only one text box for all search types
- You can search for "titanic" by entering the string "titanic".
- Search for titanic and year 1997 is as easy as typing "titanic 1997". ( not covered by unit tests yet)

Also Pipes and Directive and shared components are created whereever it made sense.

Sorting on search results hasn't been implemented as it did not make sense here. If required it can be implemented by creating a service for sorting ( AngularJS2 doens't provide inbuilt functionality).
All the pipes and directives are not fully covered with unit tests. Travis CI is the go to tool for me for continous integration and heroku for deployment.

Future Improvements:
- scss use
- unit test all units ( more scenarios).
- deployment to heroku.

`angular2-seed` provides the following features:

- Allows you to painlessly update the seed tasks of your already existing project.
- Out of the box ServiceWorkers and AppCache support thanks to the integration with [angular/mobile-toolkit](https://github.com/angular/mobile-toolkit).
- Ready to go, statically typed build system using gulp for working with TypeScript.
- Production and development builds.
- Sample unit tests with Jasmine and Karma including code coverage via [istanbul](https://gotwarlost.github.io/istanbul/).
- End-to-end tests with Protractor.
- Development server with Livereload.
- Following the [best practices](https://angular.io/styleguide).
- Manager of your type definitions using [typings](https://github.com/typings/typings).
- Has autoprefixer and css-lint support.

# How to start

**Note** that this seed project requires node v4.x.x or higher and npm 2.14.7.

**Here is how to [speed-up the build on Windows](https://github.com/mgechev/angular2-seed/wiki/Speed-up-the-build-on-Windows)**.

In order to start the seed use:

```bash
git clone --depth 1 https://github.com/mgechev/angular2-seed.git
cd angular2-seed
# install the project's dependencies
npm install
# watches your files and uses livereload by default
npm start
# api document for the app
# npm run build.docs

# dev build
npm run build.dev
# prod build
npm run build.prod
```

_Does not rely on any global dependencies._ (except Java)

# Configuration

Default application server configuration

```javascript
var PORT             = 5555;
var LIVE_RELOAD_PORT = 4002;
var DOCS_PORT        = 4003;
var APP_BASE         = '/';
```

Configure at runtime

```bash
npm start -- --port 8080 --reload-port 4000 --base /my-app/
```

# Tools documentation

A documentation of the provided tools can be found in [tools/README.md](tools/README.md).

# Running tests

```bash
npm test

# Debug - In two different shell windows
npm run build.test.watch      # 1st window
npm run karma.start           # 2nd window

# code coverage (istanbul)
# auto-generated at the end of `npm test`
# view coverage report:
npm run serve.coverage

# e2e (aka. end-to-end, integration) - In three different shell windows
# Make sure you don't have a global instance of Protractor

# npm run webdriver-update <- You will need to run this the first time
npm run webdriver-start
npm run serve.e2e
npm run e2e

# e2e live mode - Protractor interactive mode
# Instead of last command above, you can use:
npm run e2e.live
```
You can learn more about [Protractor Interactive Mode here](https://github.com/angular/protractor/blob/master/docs/debugging.md#testing-out-protractor-interactively)

<!-- # Progressive Web Apps

`angular2-seed` supports progressive web apps with [angular/mobile-toolkit](https://github.com/angular/mobile-toolkit).

The seed can generate a file `manifest.appcache` which lists all files included in a project's output, along with SHA1 hashes of all file contents. This file can be used directly as an AppCache manifest (for now, `index.html` must be manually edited to set this up).

The manifest is also annotated for use with `angular2-service-worker`. Some manual operations are currently required to enable this usage. The package must be installed, and `worker.js` manually copied into the project src directory:

```bash
cp node_modules/angular2-service-worker/dist/worker.js src/client
```

In order to generate the manifest file run:

```bash
# ENV can be both prod or dev
npm run generate.manifest -- --env ENV
```

Then, the commented snippet in `main.ts` must be uncommented to register the worker script as a service worker. -->

# Advanced Seed Option

An [advanced option to this seed exists here](https://github.com/NathanWalker/angular2-seed-advanced) which mirrors the latest changes here but adds core support for:

- [ngrx/store](https://github.com/ngrx/store) RxJS powered state management, inspired by **Redux**
- [ngrx-store-router](https://github.com/CodeSequence/ngrx-store-router) middleware for syncing state with Angular 2 Router.
- [ng2-translate](https://github.com/ocombe/ng2-translate) for i18n
- [lodash](https://lodash.com/) Helps reduce blocks of code down to single lines and enhances readability
- [NativeScript](https://www.nativescript.org/) cross platform mobile (w/ native UI) apps.
- More coming in the future...

You may use it to learn how to extend this seed for your own use cases or use the advanced seed if your project needs those features.

# Directory Structure

```
.
├── LICENSE
├── README.md
├── gulpfile.ts                <- configuration of the gulp tasks
├── karma.conf.js              <- configuration of the test runner
├── package.json               <- dependencies of the project
├── protractor.conf.js         <- e2e tests configuration
├── src                        <- source code of the application
│   └── client
│       ├── todo
│       ├── assets
│       │   └── svg
│       │       └── more.svg
│       ├── css
│       │   └── main.css
│       ├── index.html
│       ├── tsconfig.json
│       └── typings.d.ts
├── test-main.js               <- testing configuration
├── tools
│   ├── README.md              <- build documentation
│   ├── config
│   │   ├── project.config.ts  <- configuration of the specific project
│   │   ├── seed.config.interfaces.ts
│   │   └── seed.config.ts     <- generic configuration of the seed project
│   ├── config.ts              <- exported configuration (merge both seed.config and project.config, project.config overrides seed.config)
│   ├── debug.ts
│   ├── manual_typings
│   │   ├── project            <- manual ambient typings for the project
│   │   │   └── sample.package.d.ts
│   │   └── seed               <- seed manual ambient typings
│   │       ├── angular2-hot-loader.d.ts
│   │       ├── autoprefixer.d.ts
│   │       ├── colorguard.d.ts
│   │       ├── connect-livereload.d.ts
│   │       ├── cssnano.d.ts
│   │       ├── doiuse.d.ts
│   │       ├── express-history-api-fallback.d.ts
│   │       ├── istream.d.ts
│   │       ├── karma.d.ts
│   │       ├── merge-stream.d.ts
│   │       ├── open.d.ts
│   │       ├── postcss-reporter.d.ts
│   │       ├── slash.d.ts
│   │       ├── stylelint.d.ts
│   │       ├── systemjs-builder.d.ts
│   │       ├── tildify.d.ts
│   │       ├── tiny-lr.d.ts
│   │       └── walk.d.ts
│   ├── tasks                  <- gulp tasks
│   │   ├── project            <- project specific gulp tasks
│   │   │   └── sample.task.ts
│   │   └── seed               <- seed generic gulp tasks. They can be overriden by the project specific gulp tasks
│   │       ├── build.assets.dev.ts
│   │       ├── build.assets.prod.ts
│   │       ├── build.bundles.app.ts
│   │       ├── build.bundles.ts
│   │       ├── build.docs.ts
│   │       ├── build.html_css.ts
│   │       ├── build.index.dev.ts
│   │       ├── build.index.prod.ts
│   │       ├── build.js.dev.ts
│   │       ├── build.js.e2e.ts
│   │       ├── build.js.prod.ts
│   │       ├── build.js.test.ts
│   │       ├── build.js.tools.ts
│   │       ├── check.versions.ts
│   │       ├── clean.all.ts
│   │       ├── clean.dev.ts
│   │       ├── clean.prod.ts
│   │       ├── clean.tools.ts
│   │       ├── copy.js.prod.ts
│   │       ├── css-lint.ts
│   │       ├── e2e.ts
│   │       ├── generate.manifest.ts
│   │       ├── karma.start.ts
│   │       ├── serve.coverage.ts
│   │       ├── serve.docs.ts
│   │       ├── server.prod.ts
│   │       ├── server.start.ts
│   │       ├── tslint.ts
│   │       ├── watch.dev.ts
│   │       ├── watch.e2e.ts
│   │       ├── watch.test.ts
│   │       └── webdriver.ts
│   ├── utils                  <- build utils
│   │   ├── project            <- project specific gulp utils
│   │   │   └── sample_util.ts
│   │   ├── project.utils.ts
│   │   ├── seed               <- seed specific gulp utils
│   │   │   ├── clean.ts
│   │   │   ├── code_change_tools.ts
│   │   │   ├── server.ts
│   │   │   ├── tasks_tools.ts
│   │   │   ├── template_locals.ts
│   │   │   ├── tsproject.ts
│   │   │   └── watch.ts
│   │   └── seed.utils.ts
│   └── utils.ts
├── tsconfig.json              <- configuration of the typescript project (ts-node, which runs the tasks defined in gulpfile.ts)
├── tslint.json                <- tslint configuration
├── typings                    <- typings directory. Contains all the external typing definitions defined with typings
├── typings.json
└── appveyor.yml
```
# Change Log

You can follow the [Angular 2 change log here](https://github.com/angular/angular/blob/master/CHANGELOG.md).

# License

MIT


text:
package org.encuestame.business.setup;

import org.springframework.stereotype.Component;

@Component
public class InstallAdmonValidator {

    /*
     *
     * TODO: Spring Binding still use old spring version.
     * https://github.com/SpringSource/spring-webflow/blob/2.3.x/spring-binding/ivy.xml
     * This validation is disabled because make conflict with Spring Beans 3.1 version.
    public void validateinstallAdmon(AdministratorProfile administratorProfile, ValidationContext context){
        System.out.println("=============== VALIDATE 2=============");
        MessageContext messages = context.getMessageContext();
        if (!administratorProfile.getPassword().equals(administratorProfile.getConfirmPassword())) {
            messages.addMessage(new MessageBuilder().error().source("checkinDate").
                defaultText("Passwors should be equals.").build());
        }
        System.out.println("=============== VALIDATE 2=============");
    }*/
}


text: Colorful terminal printer and scanner


text:
<?php

namespace stlrnz\tests\json\converter;

use stlrnz\json\converter\Encoder;
use stlrnz\tests\json\converter\model\SimpleObject;

class EncoderRecursionTest extends \PHPUnit_Framework_TestCase
{
	/**
	 * endless recursion should fail with exception
	 */
	public function testEndlessRecursion()
	{
		$this->setExpectedException('stlrnz\json\converter\exception\EncoderException');

		$obj = new \stdClass();
		$obj->a = $obj;

		$ec = new Encoder();
		$ec->encode($obj);
	}

	/**
	 * this should not fail
	 */
	public function testRecursionComplexOK()
	{
		$obj = $this->getTestObject();

		$ec = new Encoder();
		$ec->setMaxObjectDepth(4);
		$ec->convertAssociativeArraysAsObjects();

		$ec->encode($obj);
	}

	/**
	 * this should fail
	 */
	public function testRecursionComplexFail()
	{
		$this->setExpectedException('stlrnz\json\converter\exception\EncoderException');

		$obj = $this->getTestObject();

		$ec = new Encoder();
		$ec->setMaxObjectDepth(3);
		$ec->convertAssociativeArraysAsObjects();

		$ec->encode($obj);
	}

	/**
	 * this should not fail
	 */
	public function testRecursionSimpleOK()
	{
		$obj = new \stdClass();
		$obj->a = 1;

		$ec = new Encoder();
		$ec->setMaxObjectDepth(1);

		$ec->encode($obj);
	}

	/**
	 * this should fail
	 */
	public function testRecursionSimpleFail()
	{
		$this->setExpectedException('stlrnz\json\converter\exception\EncoderException');

		$obj = new \stdClass();
		$obj->a = 1;

		$ec = new Encoder();
		$ec->setMaxObjectDepth(0);

		$ec->encode($obj);
	}

	/**
	 * method setMaxObjectDepth must be an integer
	 */
	public function testSetMaxObjectDepthException()
	{
		$this->setExpectedException('stlrnz\json\converter\exception\EncoderException');

		$ec = new Encoder();
		$ec->setMaxObjectDepth('ten');
	}

	/**
	 * @return array
	 */
	private function getTestObject()
	{
		$so = new SimpleObject();
		$so->setPriFloat(12.3);
		$so->setProInt(5);
		$so->setPubString('this is a test');

		$obj = new \stdClass();
		$obj->z = $so;

		return array(new \stdClass(), array('a' => 1, 'b' => $so, 'c' => $obj), $so);
	}
}


text:
import {Headers} from "@angular/http";
import {SelfbitsAppConfig, SbAuthSucessResponse, SbUploadFile, SbExistingFile} from "../src/utils/interfaces";

export const TESTHEADERS:Headers =  new Headers({
	'Content-Type':'application/json',
	'sb-app-id':'fancyId',
	'sb-app-secret':'fancySecret'
});

export const TESTURL:string = 'www.test.io';

export const TESTCONFIG:SelfbitsAppConfig = {
	BASE_URL: 'www.test.io',
	APP_ID: 'fancyId',
	APP_SECRET: 'fancySecret'
};

export const TESTAUTHSUCESSRES:SbAuthSucessResponse = {
	token:'fancyToken',
	userId:'fancyUserId',
	expires:'fancyExpiration'
};

export const mockUploadFile:SbUploadFile = {
	file: "contentOfTheFile",
	fileName: "theFileName",
	filePath: "the/File/Path",
	permissionScope: 'user'
}

export const mockExistingFile:SbExistingFile  = {
	fileId: "18849e2abb34c23a",
	expiresInSeconds: 600000
}

export const mockUser  = {
	userId: "userId_ab134c23a"
}

export const mockRole  = {
	name: "mockAdmin"
}


text:
package io.fabric8.monitor.plugins.jmx

import java.util.ArrayList
import java.util.List
import io.fabric8.monitor.api.DataSourceDTO

/**
 * Represents a tree of data source values
 *
 * @author Hiram Chirino
 */
class DataSourceGroup(var id: String=null, var name: String=null ) {

  var description: String = null
  var children: List[DataSourceGroup] = new ArrayList[DataSourceGroup]
  var data_sources: List[DataSourceDTO] = new ArrayList[DataSourceDTO]

  def dump(indent: Int, concise: Boolean) {
    import collection.JavaConversions._

    def print_indent(indent: Int) = for (i <- 0.to(indent)) {
      print("  ")
    }

    print_indent(indent)
    println(if (concise) id else this)

    val new_indent = indent + 1
    for (child <- children) {
      child.dump(new_indent, concise)
    }
    for (ds <- data_sources) {
      print_indent(new_indent)
      println(if (concise) ds.id else ds)
    }
  }

}


text:
package service

import (
	"context"
	"fmt"

	"github.com/graphql-go/graphql"
	"github.com/graphql-go/relay"
	"github.com/sisatech/vcli/pkg/graph"
)

const schemaString = `

type Repository {
  name: String!
  icon: Fragment
  bucket(name: String!): Bucket
  buckets(
    first: Int,
    after: String,
    last: Int,
    before: String,
    filter: String,
  ): RepositoryBucketsConnection
}

type RepositoriesNode {
  cursor: ID!
  node: Repository!
}

type RepositoriesList {
  pageInfo: PageInfo
  edges: [RepositoriesNode]!
}

type Platform {
  name: String!
  icon: Fragment
}

type PlatformsNode {
  cursor: ID!
  node: Platform!
}

type PlatformsList {
  pageInfo: PageInfo
  edges: [PlatformsNode]!
}

type Project {
  name: String!
  icon: Fragment
}

type ProjectsNode {
  cursor: ID!
  node: Project!
}

type ProjectsList {
  pageInfo: PageInfo
  edges: [ProjectsNode]!
}

type VM {
  name: String!
  icon: Fragment
}

type VMsNode {
  cursor: ID!
  node: VM!
}

type VMsList {
  pageInfo: PageInfo
  edges: [VMsNode]!
}

type PageInfo {
  startCursor: ID
  endCursor: ID
  hasPreviousPage: Boolean
  hasNextPage: Boolean
}

type Fragment {
  id: String
  url: String
}

type Query {
  repository(name: String!): Repository
  repositories(
    first: Int,
    after: String,
    last: Int,
    before: String,
    filter: String,
  ): RepositoriesList
}`

// Graph TODO: document
type Graph struct {
	repo   *graph.Graph
	schema schema
}

type schema struct {
	connRepositoryBuckets *relay.GraphQLConnectionDefinitions
	typeQuery             *graphql.Object
	schema                graphql.Schema
}

// Schema returns a string representation of the graph schema, which may be
// helpful for the purposes of documentation or development.
func (g *Graph) Schema() string {
	return fmt.Sprintf("%s\n%s", schemaString, g.repo.Schema.String())
}

func (g *Graph) build() error {

	var repoLogic graph.BusinessLogic

	var e error
	g.repo, e = graph.NewSubmodule(repoLogic)
	if e != nil {
		return e
	}

	g.schema.connRepositoryBuckets = relay.ConnectionDefinitions(relay.ConnectionConfig{
		Name:     "Bucket",
		NodeType: g.repo.Schema.TypeBucket,
	})
	g.schema.typeQuery = graphql.NewObject(graphql.ObjectConfig{
		Name:        "Query",
		Description: "", // TODO: document
		Fields: graphql.Fields{
			"name": &graphql.Field{
				Type:        graphql.String,
				Description: "", // TODO: document
			},
			"icon": &graphql.Field{
				Type:        g.repo.Schema.TypeFragment,
				Description: "", // TODO: document
			},
			"bucket": &graphql.Field{
				Type:        g.repo.Schema.TypeBucket,
				Description: "",
				Args: graphql.FieldConfigArgument{
					"name": &graphql.ArgumentConfig{
						Type:        graphql.String,
						Description: "", // TODO: document
					},
				}, // TODO: implement
				Resolve: func(p graphql.ResolveParams) (interface{}, error) {
					bucket := p.Args["name"].(string)
					return repoLogic.Bucket(p.Context, bucket)
				},
			},
			"buckets": &graphql.Field{
				Type:        g.schema.connRepositoryBuckets.ConnectionType,
				Description: "",                   // TODO: document
				Args:        relay.ConnectionArgs, // TODO: add filtering
				Resolve: func(p graphql.ResolveParams) (interface{}, error) {
					/* Method is complicated in an attempt to reduce unnecessary calls to
					 * backend business repoLogic. We first get a list of bucket names and
					 * allow the relay package to determine which ones will be returned.
					 * Afterwards, we lookup the information for the buckets that are
					 * returned.
					 */
					args := relay.NewConnectionArguments(p.Args)
					buckets, err := repoLogic.Buckets(p.Context)
					if err != nil {
						return nil, err
					}

					// get list of every bucket available
					var list []interface{}
					for _, bucket := range buckets {
						list = append(list, bucket)
					}

					// relay package filters list to determine output
					conn := relay.ConnectionFromArray(list, args)
					m := make(map[string]bool)

					// add results of relay filtering to a map (acting like a set)
					// we use this to determine if values are included in output in
					// the next range loop.
					for _, edge := range conn.Edges {
						m[edge.Node.(string)] = true
					}

					// loop through original (full) list of buckets, and substitute
					// their names (strings) for their Bucket objects if they appeared
					// in relay's filtered results.
					for i := 0; i < len(list); i++ {
						id := list[i].(string)
						if m[id] {
							a, err := repoLogic.Bucket(p.Context, id)
							if err != nil {
								return nil, err
							}
							list[i] = a
						}
					}

					// return results
					return relay.ConnectionFromArray(list, args), nil
				},
			},
		},
	})

	g.schema.schema, e = graphql.NewSchema(graphql.SchemaConfig{
		Query: g.schema.typeQuery,
	})
	if e != nil {
		return e
	}

	return nil
}

// Query returns the result of a GraphQL query when applied to the Graph. This
// result will typically be processed with 'json.Marshal' by the caller to
// produce the desired result string.
//
// The provided context will be passed to all BusinessLogic functions, allowing
// the caller to pass through arbitrary arguments such as authentication
// information to the business logic.
func (g *Graph) Query(query string) *graphql.Result {

	params := graphql.Params{
		Context:       context.Background(),
		Schema:        g.schema.schema,
		RequestString: query,
	}

	result := graphql.Do(params)
	return result
}


text:
title: The Bacchae
playwright: Euripedes
period: Autumn
season: In House
season_sort: 80
date_start: 2021-12-01
date_end: 2021-12-04
venue: New Theatre

cast:
- role: Pentheus
  name: Cameron Bullock
- role: Dionysus
  name: Jess Beedle-Platt
- role: Agave
  name: Hettie Rockell
- role: Cadmus
  name: Adam Pink
- role: Tiresias
  name: Megan Terry
- role: Messenger
  name: Ellie Harding
- role: Servant
  name: Emily Stribbling
- role: Barman
  name: Jenny Tucker

crew:
- role: Director
  name: Jasmine Butler
- role: Assistant Director
  name: Nay Dhanak
- role: Shadow Director
  name: Hannah Grant
- role: Producer
  name: Melina Williams
- role: Producer
  name: Syania Shaharuddin
- role: Shadow Producer
  name: Maria Stav
- role: Set Designer
  name: Pete Rouse
- role: Set Assistant
  name: Ylana Gibert
- role: Creative Assistant
  name: Annie Westbury
- role: Creative Assistant
  name: Katty Joseph-Martinez
- role: Lighting Designer
  name: Adam Phillips
- role: Sound Designer
  name: Annamarie Schooling
- role: Publicity Assistant
  name: Alice Rowe
- role: Set Designer
  name: Xinyue Liu
- role: Dramaturg
  name: Nay Dhanak
- role: Poster Designer
  name: Maria Stav
- role: Stage Manager
  name: Kishan Ganatra
- role: Deputy Stage Manager
  name: Xinyue Liu
- role: Assistant Stage Manager
  name: Laura Sherratt

assets:
  - type: poster
    image: GgGj3rm

---

Euripides' classic Greek tradegy of chaos, destruction and the immortal power of a god reimagined. A city falls into chaos as the local gay bar clashes heads with the uptight, arrogant politican Pentheus. Watch his world crumble as he realises the price you pay when you butt heads with a god


text:
package org.jkiss.dbeaver.ui.editors;

import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.ui.IElementFactory;
import org.eclipse.ui.IMemento;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.DBPDataSourceContainer;
import org.jkiss.dbeaver.model.DBUtils;
import org.jkiss.dbeaver.model.app.DBPProject;
import org.jkiss.dbeaver.model.exec.DBCExecutionContext;
import org.jkiss.dbeaver.model.navigator.DBNDatabaseNode;
import org.jkiss.dbeaver.model.navigator.DBNModel;
import org.jkiss.dbeaver.runtime.DBWorkbench;
import org.jkiss.utils.CommonUtils;

public class DatabaseEditorInputFactory implements IElementFactory
{
    private static final Log log = Log.getLog(DatabaseEditorInputFactory.class);

    public static final String ID_FACTORY = DatabaseEditorInputFactory.class.getName(); //$NON-NLS-1$

    private static final String TAG_CLASS = "class"; //$NON-NLS-1$
    private static final String TAG_DATA_SOURCE = "data-source"; //$NON-NLS-1$
    private static final String TAG_NODE = "node"; //$NON-NLS-1$
    private static final String TAG_NODE_NAME = "node-name"; //$NON-NLS-1$
    private static final String TAG_ACTIVE_PAGE = "page"; //$NON-NLS-1$
    private static final String TAG_ACTIVE_FOLDER = "folder"; //$NON-NLS-1$

    private static volatile boolean lookupEditor;

    public DatabaseEditorInputFactory()
    {
    }

    public static void setLookupEditor(boolean lookupEditor) {
        DatabaseEditorInputFactory.lookupEditor = lookupEditor;
    }

    @Override
    public IAdaptable createElement(IMemento memento)
    {
        // Get the node path.
        final String inputClass = memento.getString(TAG_CLASS);
        final String nodePath = memento.getString(TAG_NODE);
        final String nodeName = memento.getString(TAG_NODE_NAME);
        final String dataSourceId = memento.getString(TAG_DATA_SOURCE);
        if (nodePath == null || inputClass == null || dataSourceId == null) {
            log.error("Corrupted memento"); //$NON-NLS-2$
            return null;
        }
        final String activePageId = memento.getString(TAG_ACTIVE_PAGE);
        final String activeFolderId = memento.getString(TAG_ACTIVE_FOLDER);

        final DBPDataSourceContainer dataSourceContainer = DBUtils.findDataSource(dataSourceId);
        if (dataSourceContainer == null) {
            log.error("Can't find data source '" + dataSourceId + "'"); //$NON-NLS-2$
            return null;
        }
        if (lookupEditor && !dataSourceContainer.isConnected()) {
            // Do not instantiate editor input if we are just looking for opened editor
            //. for some object. Connection must be instantiated.
            return null;
        }
        final DBPProject project = dataSourceContainer.getRegistry().getProject();
        final DBNModel navigatorModel = DBWorkbench.getPlatform().getNavigatorModel();
        navigatorModel.ensureProjectLoaded(project);

        return new DatabaseLazyEditorInput(dataSourceContainer, project, nodePath, nodeName, activePageId, activeFolderId);
    }

    public static void saveState(IMemento memento, DatabaseEditorInput input)
    {
        if (!DBWorkbench.getPlatform().getPreferenceStore().getBoolean(DatabaseEditorPreferences.PROP_SAVE_EDITORS_STATE)) {
            return;
        }
        final DBCExecutionContext context = input.getExecutionContext();
        if (context == null) {
            // Detached - nothing to save
            return;
        }
        if (input.getDatabaseObject() != null && !input.getDatabaseObject().isPersisted()) {
            return;
        }

        final DBNDatabaseNode node = input.getNavigatorNode();
        memento.putString(TAG_CLASS, input.getClass().getName());
        memento.putString(TAG_DATA_SOURCE, context.getDataSource().getContainer().getId());
        memento.putString(TAG_NODE, node.getNodeItemPath());
        memento.putString(TAG_NODE_NAME, node.getNodeName());
        if (!CommonUtils.isEmpty(input.getDefaultPageId())) {
            memento.putString(TAG_ACTIVE_PAGE, input.getDefaultPageId());
        }
        if (!CommonUtils.isEmpty(input.getDefaultFolderId())) {
            memento.putString(TAG_ACTIVE_FOLDER, input.getDefaultFolderId());
        }
    }

}


text:
layout: default
title: "Broadcasting And Media"

---

{% include interests/broadcasting-and-media.md %}

### Who is interested in Broadcasting And Media?

* [Michael Fabricant]({{ site.baseurl }}/members/michael-fabricant.html)


text:
The PrintUserdataState Template
-------------------------------

.. admonition:: PrintUserdataState

  smacha/src/smacha/templates/PrintUserdataState.tpl.py

.. literalinclude:: /../src/smacha/templates/PrintUserdataState.tpl.py
   :language: python


text: ActiveRecord::Base.extend(ActiveRecord::GlobalizeAccessors)


text:
class AddSomeFieldsToProjects < ActiveRecord::Migration[4.2]
  def change
    change_table :projects, bulk: true do |t|
      t.column :name, :string
      t.column :full_name, :string
      t.column :source_full_name, :string
      t.column :description, :string
      t.column :watchers_count, :integer
      t.column :language, :string
    end
  end
end


text:
#include <QMenu>
#include <QAction>
#include <QToolButton>
#include <QScopedPointer>

#include "account.h"
#include "account.h"
#include "seafile-applet.h"
#include "account-mgr.h"
#include "login-dialog.h"
#include "account-settings-dialog.h"
#include "rpc/rpc-client.h"
#include "main-window.h"
#include "init-vdrive-dialog.h"
#include "avatar-service.h"
#include "utils/paint-utils.h"

#include "account-view.h"

AccountView::AccountView(QWidget *parent)
    : QWidget(parent)
{
    setupUi(this);

    // Init account drop down menu
    account_menu_ = new QMenu;
    mAccountBtn->setMenu(account_menu_);
    mAccountBtn->setPopupMode(QToolButton::InstantPopup);

    onAccountChanged();

    connect(AvatarService::instance(), SIGNAL(avatarUpdated(const QString&, const QImage&)),
            this, SLOT(updateAvatar()));

    mAccountBtn->setCursor(Qt::PointingHandCursor);
}

void AccountView::showAddAccountDialog()
{
    LoginDialog dialog(this);
    // Show InitVirtualDriveDialog for the first account added
    AccountManager *account_mgr = seafApplet->accountManager();
    if (dialog.exec() == QDialog::Accepted
        && account_mgr->accounts().size() == 1) {

        InitVirtualDriveDialog dialog(account_mgr->currentAccount(), seafApplet->mainWindow());
#if defined(Q_WS_WIN)
        dialog.exec();
#endif
    }
}

void AccountView::deleteAccount()
{
    QString question = tr("Are you sure to remove this account?
"
                          "Warning: All libraries of this account would be unsynced!");

    if (seafApplet->yesOrNoBox(question, this, false)) {
        const Account& account = seafApplet->accountManager()->currentAccount();
        QString error, server_addr = account.serverUrl.host();
        if (seafApplet->rpcClient()->unsyncReposByAccount(server_addr,
                                                          account.username,
                                                          &error) < 0) {

            seafApplet->warningBox(tr("Failed to unsync libraries of this account: %1").arg(error));
        }

        seafApplet->accountManager()->removeAccount(account);
    }
}

void AccountView::editAccountSettings()
{
    const Account& account = seafApplet->accountManager()->currentAccount();

    AccountSettingsDialog dialog(account, this);

    dialog.exec();
}

void AccountView::updateAccountInfoDisplay()
{
    if (seafApplet->accountManager()->hasAccount()) {
        const Account account = seafApplet->accountManager()->currentAccount();
        mEmail->setText(account.username);
        mServerAddr->setOpenExternalLinks(true);
        mServerAddr->setToolTip(tr("click to open the website"));

        QString host = account.serverUrl.host();
        QString href = account.serverUrl.toString();
        QString text = QString("%2").arg(href).arg(host);

        mServerAddr->setText(text);
    } else {
        mEmail->setText(tr("No account"));
        mServerAddr->setText(QString());
    }

    updateAvatar();
}

/**
 * Update the account menu when accounts changed
 */
void AccountView::onAccountChanged()
{
    const std::vector<Account>& accounts = seafApplet->accountManager()->accounts();

    // Remove all menu items
    account_menu_->clear();

    if (!accounts.empty()) {
        for (int i = 0, n = accounts.size(); i < n; i++) {
            Account account = accounts[i];
            QAction *action = makeAccountAction(accounts[i]);
            if (i == 0) {
                action->setIcon(::getMenuIconSet(":/images/account-checked.png"));
                action->setIconVisibleInMenu(true);
            }
            account_menu_->addAction(action);
        }

        account_menu_->addSeparator();
    }

    if (!accounts.empty()) {
        account_settings_action_ = new QAction(tr("Account settings"), this);
        account_settings_action_->setIcon(::getMenuIconSet(":/images/account-settings.png"));
        account_settings_action_->setIconVisibleInMenu(true);
        connect(account_settings_action_, SIGNAL(triggered()), this, SLOT(editAccountSettings()));
        account_menu_->addAction(account_settings_action_);
    }

    add_account_action_ = new QAction(tr("Add an account"), this);
    add_account_action_->setIcon(::getMenuIconSet(":/images/add-account.png"));
    add_account_action_->setIconVisibleInMenu(true);
    connect(add_account_action_, SIGNAL(triggered()), this, SLOT(showAddAccountDialog()));
    account_menu_->addAction(add_account_action_);

    if (!accounts.empty()) {
        delete_account_action_ = new QAction(tr("Delete this account"), this);
        delete_account_action_->setIcon(::getMenuIconSet(":/images/delete-account.png"));
        delete_account_action_->setIconVisibleInMenu(true);
        connect(delete_account_action_, SIGNAL(triggered()), this, SLOT(deleteAccount()));
        account_menu_->addAction(delete_account_action_);
    }

    updateAccountInfoDisplay();
}

QAction* AccountView::makeAccountAction(const Account& account)
{
    QString text = account.username + "(" + account.serverUrl.host() + ")";
    QAction *action = new QAction(text, account_menu_);
    action->setData(QVariant::fromValue(account));
    // action->setCheckable(true);
    // QMenu won't display tooltip for menu item
    // action->setToolTip(account.serverUrl.host());

    connect(action, SIGNAL(triggered()), this, SLOT(onAccountItemClicked()));

    return action;
}

// Switch to the clicked account in the account menu
void AccountView::onAccountItemClicked()
{
    QAction *action = (QAction *)(sender());
    Account account = qvariant_cast<Account>(action->data());

    seafApplet->accountManager()->setCurrentAccount(account);
}

void AccountView::updateAvatar()
{
    int w = ::getDPIScaledSize(32);
    mAccountBtn->setIconSize(QSize(w, w));
    const Account account = seafApplet->accountManager()->currentAccount();
    if (!account.isValid())  {
        mAccountBtn->setIcon(QIcon(":/images/account.png"));
        return;
    }

    AvatarService *service = AvatarService::instance();

    if (service->avatarFileExists(account.username)) {
        QString icon_path = AvatarService::instance()->getAvatarFilePath(account.username);
        mAccountBtn->setIcon(QIcon(icon_path));
        return;
    }

    mAccountBtn->setIcon(QIcon(":/images/account.png"));
    // will trigger a GetAvatarRequest
    service->getAvatar(account.username);
}