text:
LPMTX2 is a new experiment with hva LPMT updated to of0.9.x
------------------------------------------------------------

done
----

*loads 3D Models *(I still have depth configuration problem).

*global grid (for multiprojection calibration)

*Display Number Banner (multiprojectionID)

*gui has been linked in every quad to second page

Todo
----

*undo/redo history

*autosave

*enable saving deform grid dots

*run while load/save dialog active

*mask paintbrush mode

*fix 3d Smooth Render

*more shaders

*interactive quad

*quads presets

*DMX control (as already claimed)

*midi mapping

Screenshots:
------------
model in Wire texture mode loaded to quad ...

![Alt tag](https://raw.github.com/giladx/lpmt/master/bin/data/img/3d1.png)

![Alt tag](https://raw.github.com/giladx/lpmt/master/bin/data/img/3d2.png)

![Alt tag](https://raw.github.com/giladx/lpmt/master/bin/data/img/3d3.png)

![Alt tag](https://raw.github.com/giladx/lpmt/master/bin/data/img/3d4.png)

The Source
-----------

LPMT - Little Projection-Mapping Tool
---------------------------------------
(C) 2011, HVA - Hermanitos Verdes Architetti / Modena, Italy

[![Flattr this git repo](http://api.flattr.com/button/flattr-badge-large.png)](https://flattr.com/submit/auto?user_id=hv_francesco&url=https://github.com/hvfrancesco/lpmt&title=LPMT Little Projection-Mapping Tool&language=&tags=github&category=software)

LPMT is a little projection-mapping tool for use in our office,
it is developed in C++ using OpenFrameworks.
It's based on simple quad warping paradigm, and, though rather simple, can
be used to achieve complex and professional projection-mapping sets.

This is the up-to-date version of lpmt, based on OpenFrameworks 007

DOWNLOAD:
----------

At the moment LPMT is only available as source code, and we've only tested it on linux systems
but thanks to the multi-platform nature of OpenFrameworks it should work out-of-the-box on
Windows and OsX too.

up-to-date code (git repository):
http://gitorious.org/projection-mapping

for the github fans, the repository is mirrored here:
https://github.com/hvfrancesco/ProjectionMapping

if you don't like git, you can find a rarely updated zip file:
http://www.hv-a.com/projectTiles/projection-mapping.zip

MAIN FEATURES:
--------------

* up to 36 independent projection surfaces (remember you can use a solid black quad even as a mask)
* possible content: solid color, images, video, live-cam, slideshows, smoothly changing solid colors, and more …
* customizable green-screen (chromakey) for video and live-cam sources
* horizontal and vertical flipping for image, video and live-cam content
* independent opacity settings for each content element
* customizable colorization for each content element
* several blending-modes for projection surfaces
* on-screen editable masks
* bezier-warping for projection on curved surfaces
* grid-warping, with user defined grid density
* spherize deformation preset
* realtime live-masking with Kinect
* customizable video speed and volume
* save/load project set to/from xml file
* syncronized start for video elements
* vertex snap function for adjacent quads
* cam snapshot background for rough positioning of projection surfaces
* customizable speed for slideshows and color transitions
* synced multi-projectors shows with adjustable edge-blending
* control and setup through a rich set of OSC messages
* a powerful timeline to trigger events and control LPMT projections

KEY COMMANDS:
-------------

's' – saves settings to xml (projection_settings.xml in data folder)
'l' – loads settings from xml file

'a' – adds new quad
'>' – go to next quad
'<' – go to previous quad
'+' - raise active quad position in layers pile
'-' - lower active quad position in layers pile
'z' – selects first gui page for active quad settings
'x' – selects second gui page for active quad settings
'c' – selects gui page for active quad corner position fine-tuning
'q' – fills window with active quad
'1' – shows general settings page of gui

'g' – toggles gui (for quad warping with mouse gui must be switched off)
'f' – toggles fullscreen mode
'w' – toggles cam snapshot window background
'm' – toggles mask-editing mode
'b' – toggles surface bezier/grid warping editing mode

'spacebar' – toggles projection/setup modes
'r' – resyncs all videos and slideshows in all quads to starting point
'p' – starts projection
'o' – stops projection

'n' – connects to a MostPixelsEver sync server

'F10' – toggles timeline interface
'F9' – toggles timeline BPM reference grid
'F11' – toggles stage visibility under timeline
'F12' – play/stop timeline

TODO:
----------

- midi control
- DMX control
- timeline sync with MTC midi

CONTACT:
----------

you can contact us at:
francesco[at]hv-a.com

-------------------------------------------------------------------------------

this README was last edited by hv_francesco on Wed Feb 23, 2011 19:54 GMT+1,
edited 1 times in total.

__________________________________

HVA - hermanitos verdes architetti
modena - italy
www.hv-a.com
=======

# lpmtX2
the new version of hva lpmt
updated to of0.9.x


text:
package com.intellij.lang.java.parser.declarationParsing;

import com.intellij.lang.java.parser.JavaParsingTestCase;

public abstract class FieldParsingTest extends JavaParsingTestCase {
  public FieldParsingTest() {
    super("parser-full/declarationParsing/field");
  }

  public void testSimple() { doTest(true); }
  public void testMulti() { doTest(true); }

  public void testUnclosedBracket() { doTest(true); }
  public void testMissingInitializer() { doTest(true); }
  public void testUnclosedComma() { doTest(true); }
  public void testUnclosedSemicolon() { doTest(true); }
  public void testMissingInitializerExpression() { doTest(true); }

  public void testMultiLineUnclosed0() { doTest(true); }
  public void testMultiLineUnclosed1() { doTest(true); }

  public void testComplexInitializer() { doTest(true); }

  public void testErrors() { doTest(true); }
}

redpajama_set_name: RedPajamaGithub


text:
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Runtime.Remoting.Messaging;
using System.Web;
using Umbraco.Core.Composing;
using Umbraco.Core.Events;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence;

#if DEBUG_SCOPES
using System.Linq;
#endif

namespace Umbraco.Core.Scoping
{
    /// <summary>
    /// Implements <see cref="IScopeProvider"/>.
    /// </summary>
    internal class ScopeProvider : IScopeProvider, IScopeAccessor
    {
        private readonly ILogger _logger;
        private readonly FileSystems _fileSystems;

        public ScopeProvider(IUmbracoDatabaseFactory databaseFactory, FileSystems fileSystems, ILogger logger)
        {
            DatabaseFactory = databaseFactory;
            _fileSystems = fileSystems;
            _logger = logger;

            // take control of the FileSystems
            _fileSystems.IsScoped = () => AmbientScope != null && AmbientScope.ScopedFileSystems;

            _scopeReference = new ScopeReference(this);
        }

        static ScopeProvider()
        {
            SafeCallContext.Register(
                () =>
                {
                    var scope = GetCallContextObject<Scope>(ScopeItemKey);
                    var context = GetCallContextObject<ScopeContext>(ContextItemKey);
                    SetCallContextObject(ScopeItemKey, null);
                    SetCallContextObject(ContextItemKey, null);
                    return Tuple.Create(scope, context);
                },
                o =>
                {
                    // cannot re-attached over leaked scope/context
                    if (GetCallContextObject<Scope>(ScopeItemKey) != null)
                            throw new Exception("Found leaked scope when restoring call context.");
                    if (GetCallContextObject<ScopeContext>(ContextItemKey) != null)
                        throw new Exception("Found leaked context when restoring call context.");

                    var t = (Tuple<Scope, ScopeContext>) o;
                    SetCallContextObject(ScopeItemKey, t.Item1);
                    SetCallContextObject(ContextItemKey, t.Item2);
                });
        }

        public IUmbracoDatabaseFactory DatabaseFactory { get; }

        public ISqlContext SqlContext => DatabaseFactory.SqlContext;

        #region Context

        // objects that go into the logical call context better be serializable else they'll eventually
        // cause issues whenever some cross-AppDomain code executes - could be due to ReSharper running
        // tests, any other things (see https://msdn.microsoft.com/en-us/library/dn458353(v=vs.110).aspx),
        // but we don't want to make all of our objects serializable since they are *not* meant to be
        // used in cross-AppDomain scenario anyways.
        // in addition, whatever goes into the logical call context is serialized back and forth any
        // time cross-AppDomain code executes, so if we put an "object" there, we'll can *another*
        // "object" instance - and so we cannot use a random object as a key.
        // so what we do is: we register a guid in the call context, and we keep a table mapping those
        // guids to the actual objects. the guid serializes back and forth without causing any issue,
        // and we can retrieve the actual objects from the table.
        // only issue: how are we supposed to clear the table? we can't, really. objects should take
        // care of de-registering themselves from context.

        private static readonly object StaticCallContextObjectsLock = new object();
        private static readonly Dictionary<Guid, object> StaticCallContextObjects
             = new Dictionary<Guid, object>();

#if DEBUG_SCOPES
        public Dictionary<Guid, object> CallContextObjects
        {
            get
            {
                lock (StaticCallContextObjectsLock)
                {
                    // capture in a dictionary
                    return StaticCallContextObjects.ToDictionary(x => x.Key, x => x.Value);
                }
            }
        }
#endif

        private static T GetCallContextObject<T>(string key)
            where T : class
        {
            var objectKey = CallContext.LogicalGetData(key).AsGuid();
            if (objectKey == Guid.Empty) return null;

            lock (StaticCallContextObjectsLock)
            {
                if (StaticCallContextObjects.TryGetValue(objectKey, out object callContextObject))
                {
#if DEBUG_SCOPES
                    Current.Logger.Debug<ScopeProvider>("Got " + typeof(T).Name + " Object " + objectKey.ToString("N").Substring(0, 8));
                    //_logger.Debug<ScopeProvider>("At:\r\n" + Head(Environment.StackTrace, 24));
#endif
                    return (T)callContextObject;
                }

                // hard to inject into a static method :(
                Current.Logger.Warn<ScopeProvider, string, string>("Missed {TypeName} Object {ObjectKey}", typeof(T).Name, objectKey.ToString("N").Substring(0, 8));
#if DEBUG_SCOPES
                //Current.Logger.Debug<ScopeProvider>("At:\r\n" + Head(Environment.StackTrace, 24));
#endif
                return null;
            }
        }

        private static void SetCallContextObject(string key, IInstanceIdentifiable value)
        {
#if DEBUG_SCOPES
            // manage the 'context' that contains the scope (null, "http" or "call")
            // only for scopes of course!
            if (key == ScopeItemKey)
            {
                // first, null-register the existing value
                var ambientKey = CallContext.LogicalGetData(ScopeItemKey).AsGuid();
                object o = null;
                lock (StaticCallContextObjectsLock)
                {
                    if (ambientKey != default(Guid))
                        StaticCallContextObjects.TryGetValue(ambientKey, out o);
                }
                var ambientScope = o as IScope;
                if (ambientScope != null) RegisterContext(ambientScope, null);
                // then register the new value
                var scope = value as IScope;
                if (scope != null) RegisterContext(scope, "call");
            }
#endif
            if (value == null)
            {
                var objectKey = CallContext.LogicalGetData(key).AsGuid();
                CallContext.FreeNamedDataSlot(key);
                if (objectKey == default) return;
                lock (StaticCallContextObjectsLock)
                {
#if DEBUG_SCOPES
                    Current.Logger.Debug<ScopeProvider>("Remove Object " + objectKey.ToString("N").Substring(0, 8));
                    //Current.Logger.Debug<ScopeProvider>("At:\r\n" + Head(Environment.StackTrace, 24));
#endif
                    StaticCallContextObjects.Remove(objectKey);
                }
            }
            else
            {
                // note - we are *not* detecting an already-existing value
                // because our code in this class *always* sets to null before
                // setting to a real value
                var objectKey = value.InstanceId;
                lock (StaticCallContextObjectsLock)
                {
#if DEBUG_SCOPES
                    Current.Logger.Debug<ScopeProvider>("AddObject " + objectKey.ToString("N").Substring(0, 8));
                    //Current.Logger.Debug<ScopeProvider>("At:\r\n" + Head(Environment.StackTrace, 24));
#endif
                    StaticCallContextObjects.Add(objectKey, value);
                }
                CallContext.LogicalSetData(key, objectKey);
            }
        }

        // this is for tests exclusively until we have a proper accessor in v8
        internal static Func<IDictionary> HttpContextItemsGetter { get; set; }

        private static IDictionary HttpContextItems => HttpContextItemsGetter == null
            ? HttpContext.Current?.Items
            : HttpContextItemsGetter();

        public static T GetHttpContextObject<T>(string key, bool required = true)
            where T : class
        {
            var httpContextItems = HttpContextItems;
            if (httpContextItems != null)
                return (T)httpContextItems[key];
            if (required)
                throw new Exception("HttpContext.Current is null.");
            return null;
        }

        private static bool SetHttpContextObject(string key, object value, bool required = true)
        {
            var httpContextItems = HttpContextItems;
            if (httpContextItems == null)
            {
                if (required)
                    throw new Exception("HttpContext.Current is null.");
                return false;
            }
#if DEBUG_SCOPES
            // manage the 'context' that contains the scope (null, "http" or "call")
            // only for scopes of course!
            if (key == ScopeItemKey)
            {
                // first, null-register the existing value
                var ambientScope = (IScope)httpContextItems[ScopeItemKey];
                if (ambientScope != null) RegisterContext(ambientScope, null);
                // then register the new value
                var scope = value as IScope;
                if (scope != null) RegisterContext(scope, "http");
            }
#endif
            if (value == null)
                httpContextItems.Remove(key);
            else
                httpContextItems[key] = value;
            return true;
        }

#endregion

        #region Ambient Context

        internal const string ContextItemKey = "Umbraco.Core.Scoping.ScopeContext";

        public ScopeContext AmbientContext
        {
            get
            {
                // try http context, fallback onto call context
                var value = GetHttpContextObject<ScopeContext>(ContextItemKey, false);
                return value ?? GetCallContextObject<ScopeContext>(ContextItemKey);
            }

            [Obsolete("This setter is not used and will be removed in future versions")]
            [EditorBrowsable(EditorBrowsableState.Never)]
            set
            {
                // clear both
                SetHttpContextObject(ContextItemKey, null, false);
                SetCallContextObject(ContextItemKey, null);
                if (value == null) return;

                // set http/call context
                if (SetHttpContextObject(ContextItemKey, value, false) == false)
                    SetCallContextObject(ContextItemKey, value);
            }
        }

        #endregion

        #region Ambient Scope

        internal const string ScopeItemKey = "Umbraco.Core.Scoping.Scope";
        internal const string ScopeRefItemKey = "Umbraco.Core.Scoping.ScopeReference";

        // only 1 instance which can be disposed and disposed again
        private readonly ScopeReference _scopeReference;

        IScope IScopeAccessor.AmbientScope => AmbientScope;

        // null if there is none
        public Scope AmbientScope
        {
            // try http context, fallback onto call context
            get => GetHttpContextObject<Scope>(ScopeItemKey, false)
                   ?? GetCallContextObject<Scope>(ScopeItemKey);
            set
            {
                // clear both
                SetHttpContextObject(ScopeItemKey, null, false);
                SetHttpContextObject(ScopeRefItemKey, null, false);
                SetCallContextObject(ScopeItemKey, null);
                if (value == null) return;

                // set http/call context
                if (value.CallContext == false && SetHttpContextObject(ScopeItemKey, value, false))
                    SetHttpContextObject(ScopeRefItemKey, _scopeReference);
                else
                    SetCallContextObject(ScopeItemKey, value);
            }
        }

        #endregion

        public void SetAmbient(Scope scope, ScopeContext context = null)
        {
            // clear all
            SetHttpContextObject(ScopeItemKey, null, false);
            SetHttpContextObject(ScopeRefItemKey, null, false);
            SetCallContextObject(ScopeItemKey, null);
            SetHttpContextObject(ContextItemKey, null, false);
            SetCallContextObject(ContextItemKey, null);
            if (scope == null)
            {
                if (context != null)
                    throw new ArgumentException("Must be null if scope is null.", nameof(context));
                return;
            }

            if (scope.CallContext == false && SetHttpContextObject(ScopeItemKey, scope, false))
            {
                SetHttpContextObject(ScopeRefItemKey, _scopeReference);
                SetHttpContextObject(ContextItemKey, context);
            }
            else
            {
                SetCallContextObject(ScopeItemKey, scope);
                SetCallContextObject(ContextItemKey, context);
            }
        }

        /// <inheritdoc />
        public IScope CreateDetachedScope(
            IsolationLevel isolationLevel = IsolationLevel.Unspecified,
            RepositoryCacheMode repositoryCacheMode = RepositoryCacheMode.Unspecified,
            IEventDispatcher eventDispatcher = null,
            bool? scopeFileSystems = null)
        {
            return new Scope(this, _logger, _fileSystems, true, null, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems);
        }

        /// <inheritdoc />
        public void AttachScope(IScope other, bool callContext = false)
        {
            // IScopeProvider.AttachScope works with an IScope
            // but here we can only deal with our own Scope class
            if (!(other is Scope otherScope))
                throw new ArgumentException("Not a Scope instance.");

            if (otherScope.Detachable == false)
                throw new ArgumentException("Not a detachable scope.");

            if (otherScope.Attached)
                throw new InvalidOperationException("Already attached.");

            otherScope.Attached = true;
            otherScope.OrigScope = AmbientScope;
            otherScope.OrigContext = AmbientContext;

            otherScope.CallContext = callContext;
            SetAmbient(otherScope, otherScope.Context);
        }

        /// <inheritdoc />
        public IScope DetachScope()
        {
            var ambientScope = AmbientScope;
            if (ambientScope == null)
                throw new InvalidOperationException("There is no ambient scope.");

            if (ambientScope.Detachable == false)
                throw new InvalidOperationException("Ambient scope is not detachable.");

            SetAmbient(ambientScope.OrigScope, ambientScope.OrigContext);
            ambientScope.OrigScope = null;
            ambientScope.OrigContext = null;
            ambientScope.Attached = false;
            return ambientScope;
        }

        /// <inheritdoc />
        public IScope CreateScope(
            IsolationLevel isolationLevel = IsolationLevel.Unspecified,
            RepositoryCacheMode repositoryCacheMode = RepositoryCacheMode.Unspecified,
            IEventDispatcher eventDispatcher = null,
            bool? scopeFileSystems = null,
            bool callContext = false,
            bool autoComplete = false)
        {
            var ambientScope = AmbientScope;
            if (ambientScope == null)
            {
                var ambientContext = AmbientContext;
                var newContext = ambientContext == null ? new ScopeContext() : null;
                var scope = new Scope(this, _logger, _fileSystems, false, newContext, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems, callContext, autoComplete);
                // assign only if scope creation did not throw!
                SetAmbient(scope, newContext ?? ambientContext);
                return scope;
            }

            var nested = new Scope(this, _logger, _fileSystems, ambientScope, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems, callContext, autoComplete);
            SetAmbient(nested, AmbientContext);
            return nested;
        }

        public void Reset()
        {
            var scope = AmbientScope;
            scope?.Reset();

            _scopeReference.Dispose();
        }

        /// <inheritdoc />
        public IScopeContext Context => AmbientContext;

#if DEBUG_SCOPES
        // this code needs TLC
        //
        // the idea here is to keep in a list all the scopes that have been created, and to remove them
        // when they are disposed, so we can track leaks, ie scopes that would not be properly taken
        // care of by our code
        //
        // note: the code could probably be optimized... but this is NOT supposed to go into any real
        // live build, either production or debug - it's just a debugging tool for the time being

        // helps identifying when non-httpContext scopes are created by logging the stack trace
        //private void LogCallContextStack()
        //{
        //    var trace = Environment.StackTrace;
        //    if (trace.IndexOf("ScheduledPublishing") > 0)
        //        LogHelper.Debug<ScopeProvider>("CallContext: Scheduled Publishing");
        //    else if (trace.IndexOf("TouchServerTask") > 0)
        //        LogHelper.Debug<ScopeProvider>("CallContext: Server Registration");
        //    else if (trace.IndexOf("LogScrubber") > 0)
        //        LogHelper.Debug<ScopeProvider>("CallContext: Log Scrubber");
        //    else
        //        LogHelper.Debug<ScopeProvider>("CallContext: " + Environment.StackTrace);
        //}

        // all scope instances that are currently being tracked
        private static readonly object StaticScopeInfosLock = new object();
        private static readonly Dictionary<IScope, ScopeInfo> StaticScopeInfos = new Dictionary<IScope, ScopeInfo>();

        public IEnumerable<ScopeInfo> ScopeInfos
        {
            get
            {
                lock (StaticScopeInfosLock)
                {
                    return StaticScopeInfos.Values.ToArray(); // capture in an array
                }
            }
        }

        public ScopeInfo GetScopeInfo(IScope scope)
        {
            lock (StaticScopeInfosLock)
            {
                ScopeInfo scopeInfo;
                return StaticScopeInfos.TryGetValue(scope, out scopeInfo) ? scopeInfo : null;
            }
        }

        //private static void Log(string message, UmbracoDatabase database)
        //{
        //    LogHelper.Debug<ScopeProvider>(message + " (" + (database == null ? "" : database.InstanceSid) + ").");
        //}

        // register a scope and capture its ctor stacktrace
        public void RegisterScope(IScope scope)
        {
            lock (StaticScopeInfosLock)
            {
                if (StaticScopeInfos.ContainsKey(scope)) throw new Exception("oops: already registered.");
                _logger.Debug<ScopeProvider>("Register " + scope.InstanceId.ToString("N").Substring(0, 8));
                StaticScopeInfos[scope] = new ScopeInfo(scope, Environment.StackTrace);
            }
        }

        // register that a scope is in a 'context'
        // 'context' that contains the scope (null, "http" or "call")
        public static void RegisterContext(IScope scope, string context)
        {
            lock (StaticScopeInfosLock)
            {
                ScopeInfo info;
                if (StaticScopeInfos.TryGetValue(scope, out info) == false) info = null;
                if (info == null)
                {
                    if (context == null) return;
                    throw new Exception("oops: unregistered scope.");
                }
                var sb = new StringBuilder();
                var s = scope;
                while (s != null)
                {
                    if (sb.Length > 0) sb.Append(" < ");
                    sb.Append(s.InstanceId.ToString("N").Substring(0, 8));
                    var ss = s as Scope;
                    s = ss?.ParentScope;
                }
                Current.Logger.Debug<ScopeProvider>("Register " + (context ?? "null") + " context " + sb);
                if (context == null) info.NullStack = Environment.StackTrace;
                //Current.Logger.Debug<ScopeProvider>("At:\r\n" + Head(Environment.StackTrace, 16));
                info.Context = context;
            }
        }

        private static string Head(string s, int count)
        {
            var pos = 0;
            var i = 0;
            while (i < count && pos >= 0)
            {
                pos = s.IndexOf("\r\n", pos + 1, StringComparison.OrdinalIgnoreCase);
                i++;
            }
            if (pos < 0) return s;
            return s.Substring(0, pos);
        }

        public void Disposed(IScope scope)
        {
            lock (StaticScopeInfosLock)
            {
                if (StaticScopeInfos.ContainsKey(scope))
                {
                    // enable this by default
                    //Console.WriteLine("unregister " + scope.InstanceId.ToString("N").Substring(0, 8));
                    StaticScopeInfos.Remove(scope);
                    _logger.Debug<ScopeProvider>("Remove " + scope.InstanceId.ToString("N").Substring(0, 8));

                    // instead, enable this to keep *all* scopes
                    // beware, there can be a lot of scopes!
                    //info.Disposed = true;
                    //info.DisposedStack = Environment.StackTrace;
                }
            }
        }
#endif
    }

#if DEBUG_SCOPES
    public class ScopeInfo
    {
        public ScopeInfo(IScope scope, string ctorStack)
        {
            Scope = scope;
            Created = DateTime.Now;
            CtorStack = ctorStack;
        }

        public IScope Scope { get; } // the scope itself

        // the scope's parent identifier
        public Guid Parent => ((Scope) Scope).ParentScope == null ? Guid.Empty : ((Scope) Scope).ParentScope.InstanceId;

        public DateTime Created { get; } // the date time the scope was created
        public bool Disposed { get; set; } // whether the scope has been disposed already
        public string Context { get; set; } // the current 'context' that contains the scope (null, "http" or "lcc")

        public string CtorStack { get; } // the stacktrace of the scope ctor
        public string DisposedStack { get; set; } // the stacktrace when disposed
        public string NullStack { get; set; } // the stacktrace when the 'context' that contains the scope went null
    }
#endif
}


text:
#pragma once

#include "../impl/_var_id.hpp"
#include "../tags/Logic.hpp"
#include "../Features.hpp"

#include <cstdio>
#include <vector>

#include <boost/proto/debug.hpp>
#include <boost/any.hpp>
#include <boost/foreach.hpp>
#include <boost/tr1/unordered_map.hpp>
#include <boost/mpl/assert.hpp>

namespace metaSMT {
  /**
   * \ingroup Group
   */
  typedef unsigned guard_type;

  namespace features {
    struct group_api {};
  } /* features */

  struct group_change { typedef void result_type; };
  struct group_create { typedef guard_type result_type; };
  struct group_delete { typedef void result_type; };
  struct group_current { typedef guard_type result_type; };

  /**
   * \brief assertion groups.
   *
   * An API that allows grouping of constraints. groups can be freely created
   * and destroyed. The assertions and assumptions are automatically added to
   * the currently selected group. Changing group is possible at any time.
   *
   * Groups are created by adding a guard variable (implication) to each
   * expression.
   *
   * \code
   *  // enable Group API for ctx
   *  DirectSolver_Context< Group<Context> > ctx;
   *  guard_type main = current_group(ctx);
   *
   *  // create and select a group
   *  guard_type g1 = create_group(ctx);
   *  // add assertions and solve
   *  assertion( equal(True, False);
   *  solve(ctx);
   *
   *  // UNSAT, remove the Group
   *  change_group(ctx, main);
   *  delete_group(ctx, g1);
   *
   * \endcode
   *
   * Note that the current group can not be deleted because
   * the current group would be undefined or non-deterministic.
   *
   * \ingroup API
   * \defgroup Group Assertion Groups API
   * @{
   */

  template<typename Solver>
  struct Group : public Solver
  {
    typedef typename Solver::result_type result_type;
    typedef std::tr1::unordered_map < guard_type, result_type > guard_map_t;
    typedef typename guard_map_t::value_type value_pair;

    Group ()
    {
      guard_counter_ = 0;
      command ( group_create() );
    }

    void assertion ( result_type const& e )
    {
      assert ( guard_map_.find ( current_guard_ ) != guard_map_.end() );
      result_type guard = guard_map_ [ current_guard_ ] ;

      Solver::assertion ( ( *this ) ( imply_, guard, e ) );
    }

    void assumption ( result_type const& e )
    {
      assert ( guard_map_.find ( current_guard_ ) != guard_map_.end() );
      result_type guard = guard_map_ [ current_guard_ ] ;

      Solver::assumption ( ( *this ) ( imply_, guard, e ) );
    }

    bool solve ( )
    {
      BOOST_FOREACH ( value_pair g, guard_map_)
      {
        Solver::assumption ( g.second );
      }

      return Solver::solve () ;
    }

    guard_type command ( group_create const &  )
    {
      logic::tag::var_tag v = { impl::new_var_id () };

      current_guard_ = guard_counter_;
      guard_map_.insert (std::make_pair (current_guard_, ( *this) ( v, boost::any() ) ) ) ;
      ++guard_counter_;

      return current_guard_;
    }

    void command ( group_delete const &, guard_type guard )
    {
      typename guard_map_t::const_iterator iter = guard_map_.find ( guard );

      assert (guard != current_guard_ && "cannot delete current group" );
      assert (iter != guard_map_.end() && "invalid group for deletion" );

      Solver::assertion ( ( *this ) ( logic::tag::not_tag(), iter->second ) );
      guard_map_.erase ( iter );
    }

    guard_type command ( group_current const &  ) const
    {
      return current_guard_;
    }

    void command ( group_change const & , guard_type guard )
    {
      assert (guard_map_.find ( guard ) != guard_map_.end());

      current_guard_ = guard;
    }

    using Solver::command;

    private:
      guard_type                  guard_counter_;
      guard_map_t                 guard_map_;
      guard_type                  current_guard_;

      static const logic::tag::implies_tag imply_;
  };

  namespace features {
    /* Group supports group api */
    template<typename Context>
    struct supports< Group<Context>, group_api>
    : boost::mpl::true_ {};

    /* Forward all other supported operations */
    template<typename Context, typename Feature>
    struct supports< Group<Context>, Feature>
    : supports<Context, Feature>::type {};

  } /* features */

  /* group commands */

  /**
   * \brief create a new constraint group
   * \param ctx The context to work on
   * \return a handle that identifies the group
   */
  template < typename Context >
  guard_type create_group ( Context& ctx )
  {
    BOOST_MPL_ASSERT_MSG(
        ( features::supports< Context, features::group_api>::value),
        context_does_not_support_group_api,
        ()
    );
    return ctx.command ( group_create() );
  }

  /**
   * \brief delete a constraint group
   * \param ctx The context to work on
   * \param guard The group to delete
   * \return void
   *
   * Behaviour is undefined if the current group is deleted.
   * Call change_group before deleting the current group.
   */
  template < typename Context >
  void delete_group ( Context& ctx, guard_type guard )
  {
    BOOST_MPL_ASSERT_MSG(
        ( features::supports< Context, features::group_api>::value),
        context_does_not_support_group_api,
        ()
    );
    ctx.command( group_delete(), guard );
  }

  /**
   * \brief change the current constraint group
   * \param ctx The context to work on
   * \param guard The group to change to
   * \return void
   *
   */
  template < typename Context >
  void change_group ( Context& ctx, guard_type guard)
  {
    BOOST_MPL_ASSERT_MSG(
        ( features::supports< Context, features::group_api>::value),
        context_does_not_support_group_api,
        ()
    );
    ctx.command ( group_change(), guard );
  }

  /**
   * \brief get the current group guard
   * \param ctx The context to work on
   * \return The handle for the current constraint group
   */
  template < typename Context >
  guard_type current_group ( Context & ctx )
  {
    BOOST_MPL_ASSERT_MSG(
        ( features::supports< Context, features::group_api>::value),
        context_does_not_support_group_api,
        ()
    );
    return ctx.command( group_current() );
  }

  /**@}*/
} /* metaSMT */


text:
package testsuites

import (
	"context"
	"fmt"
	"path/filepath"
	"strings"

	"github.com/onsi/ginkgo/v2"
	"github.com/onsi/gomega"

	v1 "k8s.io/api/core/v1"
	storagev1 "k8s.io/api/storage/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/fields"
	"k8s.io/apimachinery/pkg/util/errors"
	clientset "k8s.io/client-go/kubernetes"
	volevents "k8s.io/kubernetes/pkg/controller/volume/events"
	"k8s.io/kubernetes/pkg/kubelet/events"
	"k8s.io/kubernetes/test/e2e/framework"
	e2eevents "k8s.io/kubernetes/test/e2e/framework/events"
	e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
	e2epv "k8s.io/kubernetes/test/e2e/framework/pv"
	e2eskipper "k8s.io/kubernetes/test/e2e/framework/skipper"
	e2evolume "k8s.io/kubernetes/test/e2e/framework/volume"
	storageframework "k8s.io/kubernetes/test/e2e/storage/framework"
	storageutils "k8s.io/kubernetes/test/e2e/storage/utils"
	admissionapi "k8s.io/pod-security-admission/api"
)

const (
	noProvisioner = "kubernetes.io/no-provisioner"
	pvNamePrefix  = "pv"
)

type volumeModeTestSuite struct {
	tsInfo storageframework.TestSuiteInfo
}

var _ storageframework.TestSuite = &volumeModeTestSuite{}

// InitCustomVolumeModeTestSuite returns volumeModeTestSuite that implements TestSuite interface
// using custom test patterns
func InitCustomVolumeModeTestSuite(patterns []storageframework.TestPattern) storageframework.TestSuite {
	return &volumeModeTestSuite{
		tsInfo: storageframework.TestSuiteInfo{
			Name:         "volumeMode",
			TestPatterns: patterns,
			SupportedSizeRange: e2evolume.SizeRange{
				Min: "1Mi",
			},
		},
	}
}

// InitVolumeModeTestSuite returns volumeModeTestSuite that implements TestSuite interface
// using testsuite default patterns
func InitVolumeModeTestSuite() storageframework.TestSuite {
	patterns := []storageframework.TestPattern{
		storageframework.FsVolModePreprovisionedPV,
		storageframework.FsVolModeDynamicPV,
		storageframework.BlockVolModePreprovisionedPV,
		storageframework.BlockVolModeDynamicPV,
	}
	return InitCustomVolumeModeTestSuite(patterns)
}

func (t *volumeModeTestSuite) GetTestSuiteInfo() storageframework.TestSuiteInfo {
	return t.tsInfo
}

func (t *volumeModeTestSuite) SkipUnsupportedTests(driver storageframework.TestDriver, pattern storageframework.TestPattern) {
}

func (t *volumeModeTestSuite) DefineTests(driver storageframework.TestDriver, pattern storageframework.TestPattern) {
	type local struct {
		config        *storageframework.PerTestConfig
		driverCleanup func()

		cs clientset.Interface
		ns *v1.Namespace
		// VolumeResource contains pv, pvc, sc, etc., owns cleaning that up
		storageframework.VolumeResource

		migrationCheck *migrationOpCheck
	}
	var (
		dInfo = driver.GetDriverInfo()
		l     local
	)

	// Beware that it also registers an AfterEach which renders f unusable. Any code using
	// f must run inside an It or Context callback.
	f := framework.NewFrameworkWithCustomTimeouts("volumemode", storageframework.GetDriverTimeouts(driver))
	f.NamespacePodSecurityEnforceLevel = admissionapi.LevelPrivileged

	init := func() {
		l = local{}
		l.ns = f.Namespace
		l.cs = f.ClientSet

		// Now do the more expensive test initialization.
		l.config, l.driverCleanup = driver.PrepareTest(f)
		l.migrationCheck = newMigrationOpCheck(f.ClientSet, f.ClientConfig(), dInfo.InTreePluginName)
	}

	// manualInit initializes l.VolumeResource without creating the PV & PVC objects.
	manualInit := func() {
		init()

		fsType := pattern.FsType
		volBindMode := storagev1.VolumeBindingImmediate

		var (
			scName             string
			pvSource           *v1.PersistentVolumeSource
			volumeNodeAffinity *v1.VolumeNodeAffinity
		)

		l.VolumeResource = storageframework.VolumeResource{
			Config:  l.config,
			Pattern: pattern,
		}

		// Create volume for pre-provisioned volume tests
		l.Volume = storageframework.CreateVolume(driver, l.config, pattern.VolType)

		switch pattern.VolType {
		case storageframework.PreprovisionedPV:
			if pattern.VolMode == v1.PersistentVolumeBlock {
				scName = fmt.Sprintf("%s-%s-sc-for-block", l.ns.Name, dInfo.Name)
			} else if pattern.VolMode == v1.PersistentVolumeFilesystem {
				scName = fmt.Sprintf("%s-%s-sc-for-file", l.ns.Name, dInfo.Name)
			}
			if pDriver, ok := driver.(storageframework.PreprovisionedPVTestDriver); ok {
				pvSource, volumeNodeAffinity = pDriver.GetPersistentVolumeSource(false, fsType, l.Volume)
				if pvSource == nil {
					e2eskipper.Skipf("Driver %q does not define PersistentVolumeSource - skipping", dInfo.Name)
				}

				storageClass, pvConfig, pvcConfig := generateConfigsForPreprovisionedPVTest(scName, volBindMode, pattern.VolMode, *pvSource, volumeNodeAffinity)
				l.Sc = storageClass
				l.Pv = e2epv.MakePersistentVolume(pvConfig)
				l.Pvc = e2epv.MakePersistentVolumeClaim(pvcConfig, l.ns.Name)
			}
		case storageframework.DynamicPV:
			if dDriver, ok := driver.(storageframework.DynamicPVTestDriver); ok {
				l.Sc = dDriver.GetDynamicProvisionStorageClass(l.config, fsType)
				if l.Sc == nil {
					e2eskipper.Skipf("Driver %q does not define Dynamic Provision StorageClass - skipping", dInfo.Name)
				}
				l.Sc.VolumeBindingMode = &volBindMode
				testVolumeSizeRange := t.GetTestSuiteInfo().SupportedSizeRange
				driverVolumeSizeRange := dInfo.SupportedSizeRange
				claimSize, err := storageutils.GetSizeRangesIntersection(testVolumeSizeRange, driverVolumeSizeRange)
				framework.ExpectNoError(err, "determine intersection of test size range %+v and driver size range %+v", testVolumeSizeRange, driverVolumeSizeRange)

				l.Pvc = e2epv.MakePersistentVolumeClaim(e2epv.PersistentVolumeClaimConfig{
					ClaimSize:        claimSize,
					StorageClassName: &(l.Sc.Name),
					VolumeMode:       &pattern.VolMode,
				}, l.ns.Name)
			}
		default:
			framework.Failf("Volume mode test doesn't support: %s", pattern.VolType)
		}
	}

	cleanup := func() {
		var errs []error
		errs = append(errs, l.CleanupResource())
		errs = append(errs, storageutils.TryFunc(l.driverCleanup))
		l.driverCleanup = nil
		framework.ExpectNoError(errors.NewAggregate(errs), "while cleaning up resource")
		l.migrationCheck.validateMigrationVolumeOpCounts()
	}

	// We register different tests depending on the drive
	isBlockSupported := dInfo.Capabilities[storageframework.CapBlock]
	switch pattern.VolType {
	case storageframework.PreprovisionedPV:
		if pattern.VolMode == v1.PersistentVolumeBlock && !isBlockSupported {
			ginkgo.It("should fail to create pod by failing to mount volume [Slow]", func() {
				manualInit()
				defer cleanup()

				var err error

				ginkgo.By("Creating sc")
				l.Sc, err = l.cs.StorageV1().StorageClasses().Create(context.TODO(), l.Sc, metav1.CreateOptions{})
				framework.ExpectNoError(err, "Failed to create sc")

				ginkgo.By("Creating pv and pvc")
				l.Pv, err = l.cs.CoreV1().PersistentVolumes().Create(context.TODO(), l.Pv, metav1.CreateOptions{})
				framework.ExpectNoError(err, "Failed to create pv")

				// Prebind pv
				l.Pvc.Spec.VolumeName = l.Pv.Name
				l.Pvc, err = l.cs.CoreV1().PersistentVolumeClaims(l.ns.Name).Create(context.TODO(), l.Pvc, metav1.CreateOptions{})
				framework.ExpectNoError(err, "Failed to create pvc")

				framework.ExpectNoError(e2epv.WaitOnPVandPVC(l.cs, f.Timeouts, l.ns.Name, l.Pv, l.Pvc), "Failed to bind pv and pvc")

				ginkgo.By("Creating pod")
				podConfig := e2epod.Config{
					NS:            l.ns.Name,
					PVCs:          []*v1.PersistentVolumeClaim{l.Pvc},
					SeLinuxLabel:  e2epod.GetLinuxLabel(),
					NodeSelection: l.config.ClientNodeSelection,
					ImageID:       e2epod.GetDefaultTestImageID(),
				}
				pod, err := e2epod.MakeSecPod(&podConfig)
				framework.ExpectNoError(err, "Failed to create pod")

				pod, err = l.cs.CoreV1().Pods(l.ns.Name).Create(context.TODO(), pod, metav1.CreateOptions{})
				framework.ExpectNoError(err, "Failed to create pod")
				defer func() {
					framework.ExpectNoError(e2epod.DeletePodWithWait(l.cs, pod), "Failed to delete pod")
				}()

				eventSelector := fields.Set{
					"involvedObject.kind":      "Pod",
					"involvedObject.name":      pod.Name,
					"involvedObject.namespace": l.ns.Name,
					"reason":                   events.FailedMountVolume,
				}.AsSelector().String()
				msg := "Unable to attach or mount volumes"

				err = e2eevents.WaitTimeoutForEvent(l.cs, l.ns.Name, eventSelector, msg, f.Timeouts.PodStart)
				// Events are unreliable, don't depend on the event. It's used only to speed up the test.
				if err != nil {
					framework.Logf("Warning: did not get event about FailedMountVolume")
				}

				// Check the pod is still not running
				p, err := l.cs.CoreV1().Pods(l.ns.Name).Get(context.TODO(), pod.Name, metav1.GetOptions{})
				framework.ExpectNoError(err, "could not re-read the pod after event (or timeout)")
				framework.ExpectEqual(p.Status.Phase, v1.PodPending, "Pod phase isn't pending")
			})
		}

	case storageframework.DynamicPV:
		if pattern.VolMode == v1.PersistentVolumeBlock && !isBlockSupported {
			ginkgo.It("should fail in binding dynamic provisioned PV to PVC [Slow][LinuxOnly]", func() {
				manualInit()
				defer cleanup()

				var err error

				ginkgo.By("Creating sc")
				l.Sc, err = l.cs.StorageV1().StorageClasses().Create(context.TODO(), l.Sc, metav1.CreateOptions{})
				framework.ExpectNoError(err, "Failed to create sc")

				ginkgo.By("Creating pv and pvc")
				l.Pvc, err = l.cs.CoreV1().PersistentVolumeClaims(l.ns.Name).Create(context.TODO(), l.Pvc, metav1.CreateOptions{})
				framework.ExpectNoError(err, "Failed to create pvc")

				eventSelector := fields.Set{
					"involvedObject.kind":      "PersistentVolumeClaim",
					"involvedObject.name":      l.Pvc.Name,
					"involvedObject.namespace": l.ns.Name,
					"reason":                   volevents.ProvisioningFailed,
				}.AsSelector().String()
				// The error message is different for each storage driver
				msg := ""

				err = e2eevents.WaitTimeoutForEvent(l.cs, l.ns.Name, eventSelector, msg, f.Timeouts.ClaimProvision)
				// Events are unreliable, don't depend on the event. It's used only to speed up the test.
				if err != nil {
					framework.Logf("Warning: did not get event about provisioning failed")
				}

				// Check the pvc is still pending
				pvc, err := l.cs.CoreV1().PersistentVolumeClaims(l.ns.Name).Get(context.TODO(), l.Pvc.Name, metav1.GetOptions{})
				framework.ExpectNoError(err, "Failed to re-read the pvc after event (or timeout)")
				framework.ExpectEqual(pvc.Status.Phase, v1.ClaimPending, "PVC phase isn't pending")
			})
		}
	default:
		framework.Failf("Volume mode test doesn't support volType: %v", pattern.VolType)
	}

	ginkgo.It("should fail to use a volume in a pod with mismatched mode [Slow]", func() {
		skipTestIfBlockNotSupported(driver)
		init()
		testVolumeSizeRange := t.GetTestSuiteInfo().SupportedSizeRange
		l.VolumeResource = *storageframework.CreateVolumeResource(driver, l.config, pattern, testVolumeSizeRange)
		defer cleanup()

		ginkgo.By("Creating pod")
		var err error
		podConfig := e2epod.Config{
			NS:           l.ns.Name,
			PVCs:         []*v1.PersistentVolumeClaim{l.Pvc},
			SeLinuxLabel: e2epod.GetLinuxLabel(),
			ImageID:      e2epod.GetDefaultTestImageID(),
		}
		pod, err := e2epod.MakeSecPod(&podConfig)
		framework.ExpectNoError(err)

		// Change volumeMounts to volumeDevices and the other way around
		pod = swapVolumeMode(pod)

		// Run the pod
		pod, err = l.cs.CoreV1().Pods(l.ns.Name).Create(context.TODO(), pod, metav1.CreateOptions{})
		framework.ExpectNoError(err, "Failed to create pod")
		defer func() {
			framework.ExpectNoError(e2epod.DeletePodWithWait(l.cs, pod), "Failed to delete pod")
		}()

		ginkgo.By("Waiting for the pod to fail")
		// Wait for an event that the pod is invalid.
		eventSelector := fields.Set{
			"involvedObject.kind":      "Pod",
			"involvedObject.name":      pod.Name,
			"involvedObject.namespace": l.ns.Name,
			"reason":                   events.FailedMountVolume,
		}.AsSelector().String()

		var msg string
		if pattern.VolMode == v1.PersistentVolumeBlock {
			msg = "has volumeMode Block, but is specified in volumeMounts"
		} else {
			msg = "has volumeMode Filesystem, but is specified in volumeDevices"
		}
		err = e2eevents.WaitTimeoutForEvent(l.cs, l.ns.Name, eventSelector, msg, f.Timeouts.PodStart)
		// Events are unreliable, don't depend on them. They're used only to speed up the test.
		if err != nil {
			framework.Logf("Warning: did not get event about mismatched volume use")
		}

		// Check the pod is still not running
		p, err := l.cs.CoreV1().Pods(l.ns.Name).Get(context.TODO(), pod.Name, metav1.GetOptions{})
		framework.ExpectNoError(err, "could not re-read the pod after event (or timeout)")
		framework.ExpectEqual(p.Status.Phase, v1.PodPending, "Pod phase isn't pending")
	})

	ginkgo.It("should not mount / map unused volumes in a pod [LinuxOnly]", func() {
		if pattern.VolMode == v1.PersistentVolumeBlock {
			skipTestIfBlockNotSupported(driver)
		}
		init()
		testVolumeSizeRange := t.GetTestSuiteInfo().SupportedSizeRange
		l.VolumeResource = *storageframework.CreateVolumeResource(driver, l.config, pattern, testVolumeSizeRange)
		defer cleanup()

		ginkgo.By("Creating pod")
		var err error
		podConfig := e2epod.Config{
			NS:           l.ns.Name,
			PVCs:         []*v1.PersistentVolumeClaim{l.Pvc},
			SeLinuxLabel: e2epod.GetLinuxLabel(),
			ImageID:      e2epod.GetDefaultTestImageID(),
		}
		pod, err := e2epod.MakeSecPod(&podConfig)
		framework.ExpectNoError(err)

		for i := range pod.Spec.Containers {
			pod.Spec.Containers[i].VolumeDevices = nil
			pod.Spec.Containers[i].VolumeMounts = nil
		}

		// Run the pod
		pod, err = l.cs.CoreV1().Pods(l.ns.Name).Create(context.TODO(), pod, metav1.CreateOptions{})
		framework.ExpectNoError(err)
		defer func() {
			framework.ExpectNoError(e2epod.DeletePodWithWait(l.cs, pod))
		}()

		err = e2epod.WaitForPodNameRunningInNamespace(l.cs, pod.Name, pod.Namespace)
		framework.ExpectNoError(err)

		// Reload the pod to get its node
		pod, err = l.cs.CoreV1().Pods(l.ns.Name).Get(context.TODO(), pod.Name, metav1.GetOptions{})
		framework.ExpectNoError(err)
		framework.ExpectNotEqual(pod.Spec.NodeName, "", "pod should be scheduled to a node")
		node, err := l.cs.CoreV1().Nodes().Get(context.TODO(), pod.Spec.NodeName, metav1.GetOptions{})
		framework.ExpectNoError(err)

		ginkgo.By("Listing mounted volumes in the pod")
		hostExec := storageutils.NewHostExec(f)
		defer hostExec.Cleanup()
		volumePaths, devicePaths, err := listPodVolumePluginDirectory(hostExec, pod, node)
		framework.ExpectNoError(err)

		driverInfo := driver.GetDriverInfo()
		volumePlugin := driverInfo.InTreePluginName
		if len(volumePlugin) == 0 {
			// TODO: check if it's a CSI volume first
			volumePlugin = "kubernetes.io/csi"
		}
		ginkgo.By(fmt.Sprintf("Checking that volume plugin %s is not used in pod directory", volumePlugin))
		safeVolumePlugin := strings.ReplaceAll(volumePlugin, "/", "~")
		for _, path := range volumePaths {
			gomega.Expect(path).NotTo(gomega.ContainSubstring(safeVolumePlugin), fmt.Sprintf("no %s volume should be mounted into pod directory", volumePlugin))
		}
		for _, path := range devicePaths {
			gomega.Expect(path).NotTo(gomega.ContainSubstring(safeVolumePlugin), fmt.Sprintf("no %s volume should be symlinked into pod directory", volumePlugin))
		}
	})
}

func generateConfigsForPreprovisionedPVTest(scName string, volBindMode storagev1.VolumeBindingMode,
	volMode v1.PersistentVolumeMode, pvSource v1.PersistentVolumeSource, volumeNodeAffinity *v1.VolumeNodeAffinity) (*storagev1.StorageClass,
	e2epv.PersistentVolumeConfig, e2epv.PersistentVolumeClaimConfig) {
	// StorageClass
	scConfig := &storagev1.StorageClass{
		ObjectMeta: metav1.ObjectMeta{
			Name: scName,
		},
		Provisioner:       noProvisioner,
		VolumeBindingMode: &volBindMode,
	}
	// PV
	pvConfig := e2epv.PersistentVolumeConfig{
		PVSource:         pvSource,
		NodeAffinity:     volumeNodeAffinity,
		NamePrefix:       pvNamePrefix,
		StorageClassName: scName,
		VolumeMode:       &volMode,
	}
	// PVC
	pvcConfig := e2epv.PersistentVolumeClaimConfig{
		AccessModes:      []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce},
		StorageClassName: &scName,
		VolumeMode:       &volMode,
	}

	return scConfig, pvConfig, pvcConfig
}

// swapVolumeMode changes volumeMounts to volumeDevices and the other way around
func swapVolumeMode(podTemplate *v1.Pod) *v1.Pod {
	pod := podTemplate.DeepCopy()
	for c := range pod.Spec.Containers {
		container := &pod.Spec.Containers[c]
		container.VolumeDevices = []v1.VolumeDevice{}
		container.VolumeMounts = []v1.VolumeMount{}

		// Change VolumeMounts to VolumeDevices
		for _, volumeMount := range podTemplate.Spec.Containers[c].VolumeMounts {
			container.VolumeDevices = append(container.VolumeDevices, v1.VolumeDevice{
				Name:       volumeMount.Name,
				DevicePath: volumeMount.MountPath,
			})
		}
		// Change VolumeDevices to VolumeMounts
		for _, volumeDevice := range podTemplate.Spec.Containers[c].VolumeDevices {
			container.VolumeMounts = append(container.VolumeMounts, v1.VolumeMount{
				Name:      volumeDevice.Name,
				MountPath: volumeDevice.DevicePath,
			})
		}
	}
	return pod
}

// listPodVolumePluginDirectory returns all volumes in /var/lib/kubelet/pods/<pod UID>/volumes/* and
// /var/lib/kubelet/pods/<pod UID>/volumeDevices/*
// Sample output:
//
//	/var/lib/kubelet/pods/a4717a30-000a-4081-a7a8-f51adf280036/volumes/kubernetes.io~secret/default-token-rphdt
//	/var/lib/kubelet/pods/4475b7a3-4a55-4716-9119-fd0053d9d4a6/volumeDevices/kubernetes.io~aws-ebs/pvc-5f9f80f5-c90b-4586-9966-83f91711e1c0
func listPodVolumePluginDirectory(h storageutils.HostExec, pod *v1.Pod, node *v1.Node) (mounts []string, devices []string, err error) {
	mountPath := filepath.Join("/var/lib/kubelet/pods/", string(pod.UID), "volumes")
	devicePath := filepath.Join("/var/lib/kubelet/pods/", string(pod.UID), "volumeDevices")

	mounts, err = listPodDirectory(h, mountPath, node)
	if err != nil {
		return nil, nil, err
	}
	devices, err = listPodDirectory(h, devicePath, node)
	if err != nil {
		return nil, nil, err
	}
	return mounts, devices, nil
}

func listPodDirectory(h storageutils.HostExec, path string, node *v1.Node) ([]string, error) {
	// Return no error if the directory does not exist (e.g. there are no block volumes used)
	_, err := h.IssueCommandWithResult("test ! -d "+path, node)
	if err == nil {
		// The directory does not exist
		return nil, nil
	}
	// The directory either exists or a real error happened (e.g. "access denied").
	// Ignore the error, "find" will hit the error again and we report it there.

	// Inside /var/lib/kubelet/pods/<pod>/volumes, look for <volume_plugin>/<volume-name>, hence depth 2
	cmd := fmt.Sprintf("find %s -mindepth 2 -maxdepth 2", path)
	out, err := h.IssueCommandWithResult(cmd, node)
	if err != nil {
		return nil, fmt.Errorf("error checking directory %s on node %s: %s", path, node.Name, err)
	}
	return strings.Split(out, "\n"), nil
}


text:
const { webpackConfig: baseClientWebpackConfig, merge } = require('shakapacker');

const commonOptions = {
  resolve: {
    extensions: ['.css', '.ts', '.tsx'],
  },
};

// add sass resource loader
const sassLoaderConfig = {
  loader: 'sass-resources-loader',
  options: {
    resources: './client/app/assets/styles/app-variables.scss',
  },
};

const scssConfigIndex = baseClientWebpackConfig.module.rules.findIndex((config) =>
  '.scss'.match(config.test),
);

baseClientWebpackConfig.module.rules[scssConfigIndex].use.push(sassLoaderConfig);

// Copy the object using merge b/c the baseClientWebpackConfig and commonOptions are mutable globals
const commonWebpackConfig = () => merge({}, baseClientWebpackConfig, commonOptions);

module.exports = commonWebpackConfig;


text:
quaggaJS
========

- [Changelog](#changelog) (2017-06-07)
- [Browser Support](#browser-support)
- [Installing](#installing)
- [Getting Started](#gettingstarted)
- [API](#api)
- [Configuration](#configobject)
- [Tips & Tricks](#tipsandtricks)
- [Sponsors](#sponsors)

## What is QuaggaJS?

QuaggaJS is a barcode-scanner entirely written in JavaScript supporting real-
time localization and decoding of various types of barcodes such as __EAN__,
__CODE 128__, __CODE 39__, __EAN 8__, __UPC-A__, __UPC-C__, __I2of5__,
__2of5__, __CODE 93__ and __CODABAR__. The library is also capable of using
`getUserMedia` to get direct access to the user's camera stream. Although the
code relies on heavy image-processing even recent smartphones are capable of
locating and decoding barcodes in real-time.

Try some [examples](https://serratus.github.io/quaggaJS/examples) and check out
the blog post ([How barcode-localization works in QuaggaJS][oberhofer_co_how])
if you want to dive deeper into this topic.

![teaser][teaser_left]![teaser][teaser_right]

## Yet another barcode library?

This is not yet another port of the great [zxing][zxing_github] library, but
more of an extension to it. This implementation features a barcode locator which
is capable of finding a barcode-like pattern in an image resulting in an
estimated bounding box including the rotation. Simply speaking, this reader is
invariant to scale and rotation, whereas other libraries require the barcode to
be aligned with the viewport.

## Browser Support

Quagga makes use of many modern Web-APIs which are not implemented by all
browsers yet. There are two modes in which Quagga operates: 1. analyzing static
images and 2. using a camera to decode the images from a live-stream. The latter
requires the presence of the MediaDevices API. You can track the compatibility
of the used Web-APIs for each mode:

- [Static Images](http://caniuse.com/#feat=webworkers,canvas,typedarrays,bloburls,blobbuilder)
- [Live Stream](http://caniuse.com/#feat=webworkers,canvas,typedarrays,bloburls,blobbuilder,stream)

### Static Images

The following APIs need to be implemented in your browser:
- [webworkers](http://caniuse.com/#feat=webworkers)
- [canvas](http://caniuse.com/#feat=canvas)
- [typedarrays](http://caniuse.com/#feat=typedarrays)
- [bloburls](http://caniuse.com/#feat=bloburls)
- [blobbuilder](http://caniuse.com/#feat=blobbuilder)

### Live Stream

In addition to the APIs mentioned above:
- [MediaDevices](http://caniuse.com/#feat=stream)

__Important:__ Accessing `getUserMedia` requires a secure origin in most
browsers, meaning that `http://` can only be used on `localhost`. All other
hostnames need to be served via `https://`. You can find more information in the
[Chrome M47 WebRTC Release Notes](https://groups.google.com/forum/#!topic/discuss-webrtc/sq5CVmY69sc).

### Feature-detection of getUserMedia

Every browser seems to differently implement the `mediaDevices.getUserMedia`
API. Therefore it's highly recommended to include
[webrtc-adapter](https://github.com/webrtc/adapter) in your project.

Here's how you can test your browser's capabilities:

```javascript
if (navigator.mediaDevices && typeof navigator.mediaDevices.getUserMedia === 'function') {
  // safely access `navigator.mediaDevices.getUserMedia`
}
```

The above condition evaluates to:

| Browser       | result  |
| ------------- |:-------:|
| Edge          | `true`  |
| Chrome        | `true`  |
| Firefox       | `true`  |
| IE 11         | `false` |
| Safari iOS    | `false` |

## Installing

QuaggaJS can be installed using __npm__, __bower__, or by including it with
the __script__ tag.

### NPM

```console
> npm install quagga
```

And then import it as dependency in your project:

```javascript
import Quagga from 'quagga'; // ES6
const Quagga = require('quagga').default; // Common JS (important: default)
```

Currently, the full functionality is only available through the browser. When
using QuaggaJS within __node__, only file-based decoding is available. See the
example for [node_examples](#node-example).

### Bower

You can also install QuaggaJS through __bower__:

```console
> bower install quagga
```

### Script-Tag Anno 1998

You can simply include `dist/quagga.min.js` in your project and you are ready
to go. The script exposes the library on the global namespace under `Quagga`.

## Getting Started

For starters, have a look at the [examples][github_examples] to get an idea
where to go from here.

## Building

You can build the library yourself by simply cloning the repo and typing:

```console
> npm install
> npm run build
```

This npm script builds a non optimized version `quagga.js` and a minified
version `quagga.min.js` and places both files in the `dist` folder.
Additionally, a `quagga.map` source-map is placed alongside these files. This
file is only valid for the non-uglified version `quagga.js` because the
minified version is altered after compression and does not align with the map
file any more.

### Node

The code in the `dist` folder is only targeted to the browser and won't work in
node due to the dependency on the DOM. For the use in node, the `build` command
also creates a `quagga.js` file in the `lib` folder.

## API

You can check out the [examples][github_examples] to get an idea of how to
use QuaggaJS. Basically the library exposes the following API:

### Quagga.init(config, callback)

This method initializes the library for a given configuration `config` (see
below) and invokes the `callback(err)` when Quagga has finished its
bootstrapping phase. The initialization process also requests for camera
access if real-time detection is configured. In case of an error, the `err`
parameter is set and contains information about the cause. A potential cause
may be the `inputStream.type` is set to `LiveStream`, but the browser does
not support this API, or simply if the user denies the permission to use the
camera.

If you do not specify a target, QuaggaJS would look for an element that matches
the CSS selector `#interactive.viewport` (for backwards compatibility).
`target` can be a string (CSS selector matching one of your DOM node) or a DOM
node.

```javascript
Quagga.init({
    inputStream : {
      name : "Live",
      type : "LiveStream",
      target: document.querySelector('#yourElement')    // Or '#yourElement' (optional)
    },
    decoder : {
      readers : ["code_128_reader"]
    }
  }, function(err) {
      if (err) {
          console.log(err);
          return
      }
      console.log("Initialization finished. Ready to start");
      Quagga.start();
  });
```

### Quagga.start()

When the library is initialized, the `start()` method starts the video-stream
and begins locating and decoding the images.

### Quagga.stop()

If the decoder is currently running, after calling `stop()` the decoder does not
process any more images. Additionally, if a camera-stream was requested upon
initialization, this operation also disconnects the camera.

### Quagga.onProcessed(callback)

This method registers a `callback(data)` function that is called for each frame
after the processing is done. The `data` object contains detailed information
about the success/failure of the operation. The output varies, depending whether
the detection and/or decoding were successful or not.

### Quagga.onDetected(callback)

Registers a `callback(data)` function which is triggered whenever a barcode-
pattern has been located and decoded successfully. The passed `data` object
contains information about the decoding process including the detected code
which can be obtained by calling `data.codeResult.code`.

### Quagga.decodeSingle(config, callback)

In contrast to the calls described above, this method does not rely on
`getUserMedia` and operates on a single image instead. The provided callback
is the same as in `onDetected` and contains the result `data` object.

### Quagga.offProcessed(handler)

In case the `onProcessed` event is no longer relevant, `offProcessed` removes
the given `handler` from the event-queue.

### Quagga.offDetected(handler)

In case the `onDetected` event is no longer relevant, `offDetected` removes
the given `handler` from the event-queue.

## The result object

The callbacks passed into `onProcessed`, `onDetected` and `decodeSingle`
receive a `data` object upon execution. The `data` object contains the following
information. Depending on the success, some fields may be `undefined` or just
empty.

```javascript
{
  "codeResult": {
    "code": "FANAVF1461710",  // the decoded code as a string
    "format": "code_128", // or code_39, codabar, ean_13, ean_8, upc_a, upc_e
    "start": 355,
    "end": 26,
    "codeset": 100,
    "startInfo": {
      "error": 1.0000000000000002,
      "code": 104,
      "start": 21,
      "end": 41
    },
    "decodedCodes": [{
      "code": 104,
      "start": 21,
      "end": 41
    },
    // stripped for brevity
    {
      "error": 0.8888888888888893,
      "code": 106,
      "start": 328,
      "end": 350
    }],
    "endInfo": {
      "error": 0.8888888888888893,
      "code": 106,
      "start": 328,
      "end": 350
    },
    "direction": -1
  },
  "line": [{
    "x": 25.97278706156836,
    "y": 360.5616435369468
  }, {
    "x": 401.9220519377024,
    "y": 70.87524989906444
  }],
  "angle": -0.6565217179979483,
  "pattern": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, /* ... */ 1],
  "box": [
    [77.4074243622672, 410.9288668804402],
    [0.050203235235130705, 310.53619724086366],
    [360.15706727788256, 33.05711026051813],
    [437.5142884049146, 133.44977990009465]
  ],
  "boxes": [
    [
      [77.4074243622672, 410.9288668804402],
      [0.050203235235130705, 310.53619724086366],
      [360.15706727788256, 33.05711026051813],
      [437.5142884049146, 133.44977990009465]
    ],
    [
      [248.90769330706507, 415.2041489551161],
      [198.9532321622869, 352.62160512937635],
      [339.546160777576, 240.3979259789976],
      [389.5006219223542, 302.98046980473737]
    ]
  ]
}
```

## Configuration

The configuration that ships with QuaggaJS covers the default use-cases and can
be fine-tuned for specific requirements.

The configuration is managed by the `config` object defining the following
high-level properties:

```javascript
{
  numOfWorkers: 4,
  locate: true,
  inputStream: {...},
  frequency: 10,
  decoder:{...},
  locator: {...},
  debug: false,
}
```

### numOfWorkers

QuaggaJS supports web-workers out of the box and runs with `4` workers in its
default configuration. The number should align with the number of cores
available in your targeted devices.

In case you don't know the number upfront, or if the variety of devices is
too big, you can either use `navigator.hardwareConcurrency` (see
[here](https://wiki.whatwg.org/wiki/Navigator_HW_Concurrency)) where available
or make use of [core-estimator](https://github.com/oftn/core-estimator).

### locate

One of the main features of QuaggaJS is its ability to locate a barcode in a
given image. The `locate` property controls whether this feature is turned on
(default) or off.

Why would someone turn this feature off? Localizing a barcode is a
computationally expensive operation and might not work properly on some
devices. Another reason would be the lack of auto-focus producing blurry
images which makes the localization feature very unstable.

However, even if none of the above apply, there is one more case where it might
be useful to disable `locate`: If the orientation, and/or the approximate
position of the barcode is known, or if you want to guide the user through a
rectangular outline. This can increase performance and robustness at the same
time.

### inputStream

The `inputStream` property defines the sources of images/videos within QuaggaJS.

```javascript
{
  name: "Live",
  type: "LiveStream",
  constraints: {
    width: 640,
    height: 480,
    facingMode: "environment",
    deviceId: "7832475934759384534"
  },
  area: { // defines rectangle of the detection/localization area
    top: "0%",    // top offset
    right: "0%",  // right offset
    left: "0%",   // left offset
    bottom: "0%"  // bottom offset
  },
  singleChannel: false // true: only the red color-channel is read
}
```

First, the `type` property can be set to three different values:
`ImageStream`, `VideoStream`, or `LiveStream` (default) and should be selected
depending on the use-case. Most probably, the default value is sufficient.

Second, the `constraint` key defines the physical dimensions of the input image
and additional properties, such as `facingMode` which sets the source of the
user's camera in case of multiple attached devices. Additionally, if required,
the `deviceId` can be set if the selection of the camera is given to the user.
This can be easily achieved via
[MediaDevices.enumerateDevices()][enumerateDevices]

Thirdly, the `area` prop restricts the decoding area of the image. The values
are given in percentage, similar to the CSS style property when using
`position: absolute`. This `area` is also useful in cases the `locate` property
is set to `false`, defining the rectangle for the user.

The last key `singleChannel` is only relevant in cases someone wants to debug
erroneous behavior of the decoder. If set to `true` the input image's red
color-channel is read instead of calculating the gray-scale values of the
source's RGB. This is useful in combination with the `ResultCollector` where
the gray-scale representations of the wrongly identified images are saved.

### frequency

This top-level property controls the scan-frequency of the video-stream. It's
optional and defines the maximum number of scans per second. This renders
useful for cases where the scan-session is long-running and resources such as
CPU power are of concern.

### decoder

QuaggaJS usually runs in a two-stage manner (`locate` is set to `true`) where,
after the barcode is located, the decoding process starts. Decoding is the
process of converting the bars into its true meaning. Most of the configuration
options within the `decoder` are for debugging/visualization purposes only.

```javascript
{
  readers: [
    'code_128_reader'
  ],
  debug: {
      drawBoundingBox: false,
      showFrequency: false,
      drawScanline: false,
      showPattern: false
  }
  multiple: false
}
```

The most important property is `readers` which takes an array of types of
barcodes which should be decoded during the session. Possible values are:

- code_128_reader (default)
- ean_reader
- ean_8_reader
- code_39_reader
- code_39_vin_reader
- codabar_reader
- upc_reader
- upc_e_reader
- i2of5_reader
- 2of5_reader
- code_93_reader

Why are not all types activated by default? Simply because one should
explicitly define the set of barcodes for their use-case. More decoders means
more possible clashes, or false-positives. One should take care of the order
the readers are given, since some might return a value even though it is not
the correct type (EAN-13 vs. UPC-A).

The `multiple` property tells the decoder if it should continue decoding after
finding a valid barcode.  If multiple is set to `true`, the results will be
returned as an array of result objects.  Each object in the array will have a
`box`, and may have a `codeResult` depending on the success of decoding the
individual box.

The remaining properties `drawBoundingBox`, `showFrequency`, `drawScanline` and
`showPattern` are mostly of interest during debugging and visualization.

#### Enabling extended EAN

The default setting for `ean_reader` is not capable of reading extensions such
as [EAN-2](https://en.wikipedia.org/wiki/EAN_2) or
[EAN-5](https://en.wikipedia.org/wiki/EAN_5). In order to activate those
supplements you have to provide them in the configuration as followed:

```javascript
decoder: {
    readers: [{
        format: "ean_reader",
        config: {
            supplements: [
                'ean_5_reader', 'ean_2_reader'
            ]
        }
    }]
}
```

Beware that the order of the `supplements` matters in such that the reader stops
decoding when the first supplement was found. So if you are interested in EAN-2
and EAN-5 extensions, use the order depicted above.

It's important to mention that, if supplements are supplied, regular EAN-13
codes cannot be read any more with the same reader. If you want to read EAN-13
with and without extensions you have to add another `ean_reader` reader to the
configuration.

### locator

The `locator` config is only relevant if the `locate` flag is set to `true`.
It controls the behavior of the localization-process and needs to be adjusted
for each specific use-case. The default settings are simply a combination of
values which worked best during development.

Only two properties are relevant for the use in Quagga (`halfSample` and
`patchSize`) whereas the rest is only needed for development and debugging.

```javascript
{
  halfSample: true,
  patchSize: "medium", // x-small, small, medium, large, x-large
  debug: {
    showCanvas: false,
    showPatches: false,
    showFoundPatches: false,
    showSkeleton: false,
    showLabels: false,
    showPatchLabels: false,
    showRemainingPatchLabels: false,
    boxFromPatches: {
      showTransformed: false,
      showTransformedBox: false,
      showBB: false
    }
  }
}
```

The `halfSample` flag tells the locator-process whether it should operate on an
image scaled down (half width/height, quarter pixel-count ) or not. Turning
`halfSample` on reduces the processing-time significantly and also helps
finding a barcode pattern due to implicit smoothing.
It should be turned off in cases where the barcode is really small and the full
resolution is needed to find the position. It's recommended to keep it turned
on and use a higher resolution video-image if needed.

The second property `patchSize` defines the density of the search-grid. The
property accepts strings of the value `x-small`, `small`, `medium`, `large` and
`x-large`. The `patchSize` is proportional to the size of the scanned barcodes.
If you have really large barcodes which can be read close-up, then the use of
`large` or `x-large` is recommended. In cases where the barcode is further away
from the camera lens (lack of auto-focus, or small barcodes) then it's advised
to set the size to `small` or even `x-small`. For the latter it's also
recommended to crank up the resolution in order to find a barcode.

## Examples

The following example takes an image `src` as input and prints the result on the
console. The decoder is configured to detect _Code128_ barcodes and enables the
locating-mechanism for more robust results.

```javascript
Quagga.decodeSingle({
    decoder: {
        readers: ["code_128_reader"] // List of active readers
    },
    locate: true, // try to locate the barcode in the image
    src: '/test/fixtures/code_128/image-001.jpg' // or 'data:image/jpg;base64,' + data
}, function(result){
    if(result.codeResult) {
        console.log("result", result.codeResult.code);
    } else {
        console.log("not detected");
    }
});
```

### Using node

The following example illustrates the use of QuaggaJS within a node
environment. It's almost identical to the browser version with the difference
that node does not support web-workers out of the box. Therefore the config
property `numOfWorkers` must be explicitly set to `0`.

```javascript
var Quagga = require('quagga').default;

Quagga.decodeSingle({
    src: "image-abc-123.jpg",
    numOfWorkers: 0,  // Needs to be 0 when used within node
    inputStream: {
        size: 800  // restrict input-size to be 800px in width (long-side)
    },
    decoder: {
        readers: ["code_128_reader"] // List of active readers
    },
}, function(result) {
    if(result.codeResult) {
        console.log("result", result.codeResult.code);
    } else {
        console.log("not detected");
    }
});
```

## Tips & Tricks

A growing collection of tips & tricks to improve the various aspects of Quagga.

### Barcodes too small?

Barcodes too far away from the camera, or a lens too close to the object
result in poor recognition rates and Quagga might respond with a lot of
false-positives.

Starting in Chrome 59 you can now make use of `capabilities` and directly
control the zoom of the camera. Head over to the
[web-cam demo](https://serratus.github.io/quaggaJS/examples/live_w_locator.html)
and check out the __Zoom__ feature.

You can read more about those `capabilities` in
[Let's light a torch and explore MediaStreamTrack's capabilities](https://www.oberhofer.co/mediastreamtrack-and-its-capabilities)

### Video too dark?

Dark environments usually result in noisy images and therefore mess with the
recognition logic.

Since Chrome 59 you can turn on/off the __Torch__ of our device and vastly
improve the quality of the images. Head over to the
[web-cam demo](https://serratus.github.io/quaggaJS/examples/live_w_locator.html)
and check out the __Torch__ feature.

To find out more about this feature [read on](https://www.oberhofer.co/mediastreamtrack-and-its-capabilities).

## Tests

Unit Tests can be run with [Karma][karmaUrl] and written using
[Mocha][mochaUrl], [Chai][chaiUrl] and [SinonJS][sinonUrl]. Coverage reports are
automatically generated in the coverage/ folder.

```console
> npm install
> npm run test
```
## Image Debugging

In case you want to take a deeper dive into the inner workings of Quagga, get to
know the _debugging_ capabilities of the current implementation. The various
flags exposed through the `config` object give you the abilily to visualize
almost every step in the processing. Because of the introduction of the
web-workers, and their restriction not to have access to the DOM, the
configuration must be explicitly set to `config.numOfWorkers = 0` in order to
work.

## ResultCollector

Quagga is not perfect by any means and may produce false positives from time
to time. In order to find out which images produced those false positives,
the built-in ``ResultCollector`` will support you and me helping squashing
bugs in the implementation.

### Creating a ``ResultCollector``

You can easily create a new ``ResultCollector`` by calling its ``create``
method with a configuration.

```javascript
var resultCollector = Quagga.ResultCollector.create({
    capture: true, // keep track of the image producing this result
    capacity: 20,  // maximum number of results to store
    blacklist: [   // list containing codes which should not be recorded
        {code: "3574660239843", format: "ean_13"}],
    filter: function(codeResult) {
        // only store results which match this constraint
        // returns true/false
        // e.g.: return codeResult.format === "ean_13";
        return true;
    }
});
```

### Using a ``ResultCollector``

After creating a ``ResultCollector`` you have to attach it to Quagga by
calling ``Quagga.registerResultCollector(resultCollector)``.

### Reading results

After a test/recording session, you can now print the collected results which
do not fit into a certain schema. Calling ``getResults`` on the
``resultCollector`` returns an ``Array`` containing objects with:

```javascript
{
    codeResult: {}, // same as in onDetected event
    frame: "data:image/png;base64,iVBOR..." // dataURL of the gray-scaled image
}
```

The ``frame`` property is an internal representation of the image and
therefore only available in gray-scale. The dataURL representation allows
easy saving/rendering of the image.

### Comparing results

Now, having the frames available on disk, you can load each single image by
calling ``decodeSingle`` with the same configuration as used during recording
. In order to reproduce the exact same result, you have to make sure to turn
on the ``singleChannel`` flag in the configuration when using ``decodeSingle``.

## Sponsors

- [Maintenance Connection Canada (Asset Pro Solutions Inc.](http://maintenanceconnection.ca/)

## Changelog

### 2017-06-07
- Improvements
  - added `muted` and `playsinline` to `<video/>` to make it work for Safari 11
  Beta (even iOS)
- Fixes
  - Fixed  [example/live_w_locator.js](https://github.com/serratus/quaggaJS/blob/master/example/live_w_locator.js)

### 2017-06-06
- Features
  - Support for Standard 2of5 barcodes (See
      [\#194](https://github.com/serratus/quaggaJS/issues/194))
  - Support for Code 93 barcodes (See
      [\#194](https://github.com/serratus/quaggaJS/issues/195))
  - Exposing `Quagga.CameraAccess.getActiveTrack()` to get access to the
      currently used `MediaStreamTrack`
    - Example can be viewed here: [example/live_w_locator.js](https://github.com/serratus/quaggaJS/blob/master/example/live_w_locator.js) and a [demo](https://serratus.github.io/quaggaJS/examples/live_w_locator.html)

Take a look at the release-notes (
    [0.12.0](https://github.com/serratus/quaggaJS/releases/tag/v0.12.0))

### 2017-01-08
- Improvements
  - Exposing `CameraAccess` module to get access to methods like
    `enumerateVideoDevices` and `getActiveStreamLabel`
    (see `example/live_w_locator`)
  - Update to webpack 2.2 (API is still unstable)

### 2016-10-03
- Fixes
  - Fixed `facingMode` issue with Chrome >= 53 (see [#128](https://github.com/serratus/quaggaJS/issues/128))

### 2016-08-15
- Features
  - Proper handling of EXIF orientation when using `Quagga.decodeSingle`
  (see [#121](https://github.com/serratus/quaggaJS/issues/121))

### 2016-04-24
- Features
  - EAN-13 extended codes can now be decoded (See
      [\#71](https://github.com/serratus/quaggaJS/issues/71))

Take a look at the release-notes (
    [0.11.0](https://github.com/serratus/quaggaJS/releases/tag/v0.11.0))

### 2016-04-19
- Improvements
  - Reducing false-positives for Code 128 barcodes (
      addresses [\#104](https://github.com/serratus/quaggaJS/issues/104))

### 2016-03-31
Take a look at the release-notes (
    [0.10.0](https://github.com/serratus/quaggaJS/releases/tag/v0.10.0))

### 2016-02-18

- Internal Changes
  - Restructuring into meaningful folders
  - Removing debug-code in production build

### 2016-02-15
Take a look at the release-notes (
    [0.9.0](https://github.com/serratus/quaggaJS/releases/tag/v0.9.0))

### 2015-11-22

- Fixes
  - Fixed inconsistencies for Code 128 decoding (See
      [\#76](https://github.com/serratus/quaggaJS/issues/76))

### 2015-11-15

- Fixes
  - Fixed inconsistency in Code 39 decoding
  - added inline-source-map to quagga.js file

### 2015-10-13
Take a look at the release-notes ([0.8.0]
(https://github.com/serratus/quaggaJS/releases/tag/v0.8.0))

- Improvements
  - Replaced RequireJS with webpack

### 2015-09-15
Take a look at the release-notes ([0.7.0]
(https://github.com/serratus/quaggaJS/releases/tag/v0.7.0))

- Features
  - Added basic support for running QuaggaJS inside __node__ (see [example]
  (#node-example))

### 2015-08-29
- Improvements
  - Added support for Internet Explorer (only Edge+ supports `getUserMedia`)

### 2015-08-13
- Improvements
  - Added `offProcessed` and `offDetected` methods for detaching event-
  listeners from the event-queue.

### 2015-07-29
- Features
  - Added basic support for [ITF][i2of5_wiki] barcodes (`i2of5_reader`)

### 2015-07-08
- Improvements
  - Parameter tweaking to reduce false-positives significantly (for the
  entire EAN and UPC family)
  - Fixing bug in parity check for UPC-E codes
  - Fixing bug in alignment for EAN-8 codes

### 2015-07-06
- Improvements
  - Added `err` parameter to [Quagga.init()](#quaggainit) callback
  function

### 2015-06-21
- Features
  - Added ``singleChannel`` configuration to ``inputStream`` (in [config]
  (#configobject))
  - Added ``ResultCollector`` functionality (see [ResultCollector]
  (#resultcollector))

### 2015-06-13
- Improvements
  - Added ``format`` property to ``codeResult`` (in [result](#resultobject))

### 2015-06-13
- Improvements
  - Added fixes for ``Code39Reader`` (trailing whitespace was missing)

### 2015-06-09
- Features
  - Introduced the ``area`` property
  - Ability to define a rectangle where localization/decoding should be applied

### 2015-05-20
- Improvements
  - Making EAN and UPC readers even more restrictive
  - Added example using requirejs

### 2015-05-18
- Improvements
  - Making EAN and UPC readers more restrictive
  - Added integration-tests for all barcode-readers

### 2015-05-09
- Improvements
  - Odd image dimensions no longer cause problems

### 2015-04-30
- Features
  - Added support for [UPC-A and UPC-E][upc_wiki] barcodes
  - Added support for [EAN-8][ean_8_wiki] barcodes
- Improvements
  - Added extended configuration to the live-video example
  - Releasing resources when calling ``Quagga.stop()``

### 2015-04-25
- Improvements
  - Added extended configuration to the file-input example
  - Configurable ``patchSize`` for better adjustment to small/medium/large
      barcodes

### 2015-04-16
- Features
  - Added support for [Codabar][codabar_wiki] barcodes

### 2015-03-16
- Improvements
  - now includes minified version (23.3KB gzipped)
  - No need for configuration of script-name any more

### 2015-03-12
- Improvements
  - removed dependency on async.js

### 2015-03-04
- Features
  - Added support for [Code 39][code39_wiki] barcodes

### 2015-01-21
- Features
  - Added support for web-worker (using 4 workers as default, can be changed
  through `config.numOfWorkers`)
  - Due to the way how web-workers are created, the name of the script file
  (`config.scriptName`) should be kept in sync with your actual filename
  - Removed canvas-overlay for decoding (boxes & scanline) which can now be
  easily implemented using the existing API (see example)
- API Changes
In the course of implementing web-workers some breaking changes were
introduced to the API.
  - The `Quagga.init` function no longer receives the callback as part of the
   config but rather as a second argument: `Quagga.init(config, cb)`
  - The callback to `Quagga.onDetected` now receives an object containing
  much more information in addition to the decoded code.(see
  [data](#resultobject))
  - Added `Quagga.onProcessed(callback)` which provides a way to get information
  for each image processed. The callback receives the same `data` object as
  `Quagga.onDetected` does. Depending on the success of the process the `data`
  object might not contain any `resultCode` and/or `box` properties.

[zxing_github]: https://github.com/zxing/zxing
[teaser_left]: https://raw.githubusercontent.com/serratus/quaggaJS/master/doc/img/mobile-located.png
[teaser_right]: https://raw.githubusercontent.com/serratus/quaggaJS/master/doc/img/mobile-detected.png
[caniuse_getusermedia]: http://caniuse.com/#feat=stream
[sinonUrl]: http://sinonjs.org/
[chaiUrl]: http://chaijs.com/
[mochaUrl]: https://github.com/mochajs/mocha
[karmaUrl]: http://karma-runner.github.io/
[code39_wiki]: http://en.wikipedia.org/wiki/Code_39
[codabar_wiki]: http://en.wikipedia.org/wiki/Codabar
[upc_wiki]: http://en.wikipedia.org/wiki/Universal_Product_Code
[ean_8_wiki]: http://en.wikipedia.org/wiki/EAN-8
[oberhofer_co_how]: http://www.oberhofer.co/how-barcode-localization-works-in-quaggajs/
[github_examples]: https://serratus.github.io/quaggaJS/examples
[i2of5_wiki]: https://en.wikipedia.org/wiki/Interleaved_2_of_5
[enumerateDevices]: https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/enumerateDevices


text:
var libdtrace = require('bindings')('dtrace.node');

module.exports=libdtrace;


text:
// Copyright 2018 The Oppia Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @fileoverview Tests for SkillRightsModel.
 */

import { SkillRights } from
  'domain/skill/skill-rights.model';

describe('Skill rights model', () => {
  it('should make a copy from another skill rights object', () => {
    const sampleSkillRightsObject1 = {
      skill_id: '1',
      can_edit_skill_description: true
    };

    const sampleSkillRightsObject2 = {
      skill_id: '2',
      can_edit_skill_description: false
    };

    const sampleSkillRights1 = SkillRights.createFromBackendDict(
      sampleSkillRightsObject1);

    const sampleSkillRights2 = SkillRights.createFromBackendDict(
      sampleSkillRightsObject2);

    sampleSkillRights2.copyFromSkillRights(sampleSkillRights1);
    expect(sampleSkillRights2.getSkillId()).toEqual('1');
    expect(sampleSkillRights2.canEditSkillDescription()).toBe(true);
  });
});


text:
from .. import *

# Item-related WTForms definitions & views

class AddItemForm(BaseForm):
    name = StringField('Title',
                       validators=[
                            DataRequired(),
                            Length(min=6, max=100,
                                   message="Title must have between " +
                                           "%(min)d and %(max)d characters")
                            ])
    description = TextAreaField('Description',
                                validators=[
                                  DataRequired(),
                                  Length(max=1000,
                                         message="Description must have 1000" +
                                                 " characters max"
                                         )
                                 ])
    categories = OpenSelectMultipleField('Categories')
    picture = FileField('Item picture')
    # 0 = unmodified; 1 = replaced; 2 = deleted
    picture_status = IntegerField('picture_status', default=0)

    def validate_picture(form, field):
        if form.picture_status.data == 1:  # validate only if it was modified
            if field.name in request.files:
                # store the file
                field.data = request.files[field.name]
                if not allowed_file(field.data.filename):
                    form.picture_status.data = 0
                    raise ValidationError('Item picture must be an image')
        else:
            field.data = None

class EditItemForm(BaseForm):
    name = StringField('Title',
                       validators=[
                            DataRequired(),
                            Length(min=6, max=100,
                                   message="Title must have between " +
                                           "%(min)d and %(max)d characters")
                            ])
    description = TextAreaField('Description',
                                validators=[
                                  DataRequired(),
                                  Length(max=1000,
                                         message="Description must have 1000" +
                                                 " characters max"
                                         )
                                 ])
    categories = OpenSelectMultipleField('Categories')
    picture = FileField('Item picture')
    # 0 = unmodified; 1 = replaced; 2 = deleted
    picture_status = IntegerField('picture_status', default=0)

    def validate_picture(form, field):
        if form.picture_status.data == 1:  # validate only if it was modified
            if field.name in request.files:
                # store the file
                field.data = request.files[field.name]
                if not allowed_file(field.data.filename):
                    form.picture_status.data = 0
                    raise ValidationError('Item picture must be an image')
        else:
            field.data = None

@app.route('/item/new', methods=['GET', 'POST'])
@login_required
def item_new():
    # New item view
    # - Displays the new item view and
    # - allows to add a new item to logged in users
    success = False
    # WTF Form to handle the submitted data
    form = AddItemForm(request.form)
    # Fill the category selectbox from the database
    form.categories.choices = [(str(g.id)+'|'+g.name, g.name) for g
                               in db_session.query(Category).order_by('name')]
    if request.method == 'POST':
        categories_selected = slugify_category_list(form.categories.data)
        # Add the new categories to the selectbox
        form.categories.choices += [(x[0], x[2]) for x in
                                    categories_selected
                                    if (x[0], x[2]) not in
                                    form.categories.choices]
        if form.validate():
            if len(categories_selected) > 0:
                # Save the new item and the categories selected
                item = Item()
                item.name = form.name.data
                item.description = form.description.data
                categories_list = []
                item.categories = categories_list
                for cat_key, cat_id, cat_slug in categories_selected:
                    if cat_id == 0:
                        # New category, create it
                        item_category = Category(name=cat_slug)
                    else:
                        # Find the category by the id
                        item_category = db_session \
                                        .query(Category) \
                                        .filter_by(id=cat_id).first()
                        if item_category is None:
                            # If it wasn't in the database, create it
                            item_category = Category(name=cat_slug)
                    categories_list.append(item_category)
                item.categories = categories_list
                item.author = current_user
                # Add item image
                if form.picture.data is not None:
                    item.picture.from_blob(
                        form.picture.data.read())
                # Save the new user
                db_session.add(item)
                db_session.commit()
                success = True
                flash("Item was created successfully")
                # Clear the form, reset the categories
                form = AddItemForm(formdata=None)
                form.categories \
                    .choices = [(str(g.id)+'|'+g.name, g.name) for g
                                in db_session.query(Category).order_by('name')]
            else:
                flash("The item must have at least one category")
    flash_errors(form)
    form.picture_status.data = 0
    return render_template('item_form.html', form=form, is_success=success)

@app.route('/item/edit/<int:item_id>', methods=['GET', 'POST'])
@login_required
def item_edit(item_id):
    # Edit item view
    # - Displays the edit item view and
    # - allows to edit an item to logged in users
    # - only if the user is the item's owner
    success = False
    # verify if the item exists and if current_user is its author
    item = db_session.query(Item) \
                     .filter(Item.id == item_id and
                             Item.author_id == current_user.id).first()
    if item is None:
        flash("You can only modify your own items")
        return redirect(url_for('index'))
    # WTF Form to handle the submitted data
    form = EditItemForm(request.form, item)
    # Fill the category selectbox from the database
    form.categories.choices = [(str(g.id)+'|'+g.name, g.name) for g
                               in db_session.query(Category).order_by('name')]
    if request.method == 'GET':
        form.picture_status.data = 0
        # Load the selected categories from the item.categories
        form.categories.data = [str(g.id)+'|'+g.name for g in item.categories]
    elif request.method == 'POST':
        categories_selected = slugify_category_list(form.categories.data)
        form.categories.choices += [(x[0], x[2]) for x in
                                    categories_selected
                                    if (x[0], x[2]) not in
                                    form.categories.choices]
        if form.validate():
            if len(categories_selected) > 0:
                item.name = form.name.data
                item.description = form.description.data
                categories_list = []
                item.categories = categories_list
                for cat_key, cat_id, cat_slug in categories_selected:
                    if cat_id == 0:
                        # New category, create it
                        item_category = Category(name=cat_slug)
                    else:
                        # Find the category by the id
                        item_category = db_session \
                                        .query(Category) \
                                        .filter_by(id=cat_id).first()
                        if item_category is None:
                            # If it wasn't in the database, create it
                            item_category = Category(name=cat_slug)
                    categories_list.append(item_category)
                item.categories = categories_list
                if form.picture_status.data == 2 \
                   or form.picture_status.data == 1:
                    # delete the current image
                    current_image = item.picture.first()
                    if current_image is not None:
                        item.picture.remove(current_image)
                if form.picture_status.data == 1:
                    if form.picture.data is not None:
                        # save the new image
                        item.picture.from_blob(
                            form.picture.data.read())
                # save the updated item
                db_session.merge(item)
                db_session.commit()
                success = True
                flash("Item was modified successfully")
                # reset the form
                form = EditItemForm(request.form, item)
                form.categories \
                    .choices = [(str(g.id)+'|'+g.name, g.name) for g
                                in db_session.query(Category).order_by('name')]
                form.categories.data = [str(g.id)+'|'+g.name for g
                                        in item.categories]
            else:
                flash("The item must have at least one category")
    flash_errors(form)
    # retrieve the current item image
    item_image_url = item.default_picture_url
    form.picture_status.data = '0'
    return render_template('item_form.html', item_image_url=item_image_url,
                           form=form, is_success=success, is_edit=True,
                           item_id=item.id)

@app.route('/item/detail/<int:item_id>')
def item_detail(item_id):
    # Detail item view
    # - Displays the detail item view, redirect to index if item doesn't exist
    item = db_session.query(Item) \
                     .filter(Item.id == item_id).first()
    if item is None:
        flash('Item does not exist')
        return redirect(url_for('index'))
    return render_template('item_detail.html', item=item)

@app.route('/item/delete/<int:item_id>', methods=['POST'])
@login_required
def item_delete(item_id):
    # Delete item action
    # - Receive the delete request for an item and
    # - allows to delete an item to logged in users
    # - only if the user is the item's owner
    item = db_session.query(Item) \
                     .filter(Item.id == item_id).first()
    if item is not None:
        if item.author_id == current_user.id:
            db_session.delete(item)
            db_session.commit()
            flash("Item deleted successfully")
        else:
            flash("You can only delete your own items")
    else:
        flash("Item does not exist")
    return redirect(url_for('index'))