    public <T extends Source> T getSource(Class<T> sourceClass) throws SQLException {
        try {
            if (isDebugEnabled()) {
                debugCode(
                        "getSource(" + (sourceClass != null ? sourceClass.getSimpleName() + ".class" : "null") + ')');
            }
            checkReadable();
            if (sourceClass == null || sourceClass == DOMSource.class) {
                DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
                return (T) new DOMSource(dbf.newDocumentBuilder().parse(new InputSource(value.getInputStream())));
            } else if (sourceClass == SAXSource.class) {
                return (T) new SAXSource(new InputSource(value.getInputStream()));
            } else if (sourceClass == StAXSource.class) {
                XMLInputFactory xif = XMLInputFactory.newInstance();
                return (T) new StAXSource(xif.createXMLStreamReader(value.getInputStream()));
            } else if (sourceClass == StreamSource.class) {
                return (T) new StreamSource(value.getInputStream());
            }
            throw unsupported(sourceClass.getName());
        } catch (Exception e) {
            throw logAndConvert(e);
        }
    }


	protected void initUpgradesHistories() {
		File upgradesDir = new File(WebappHelper.getUserDataRoot(), SYSTEM_DIR);
		File upgradesHistoriesFile = new File(upgradesDir, INSTALLED_UPGRADES_XML);
		if (upgradesHistoriesFile.exists()) {
			upgradesHistories = (Map<String, UpgradeHistoryData>)upgradesXStream.fromXML(upgradesHistoriesFile);
		} else {
			if (upgradesHistories == null) {
				upgradesHistories = new HashMap<>();
			}
			needsUpgrade = false; //looks like a new install, no upgrade necessary
			log.info("This looks like a new install or dropped data, will not do any upgrades.");
			createUpgradeData();
		}
	}


    public InternetAddress getUserEmail()
    {
        return userEmail;
    }


    private String getMimeType(HttpServletRequest pReq) {
        String requestMimeType = pReq.getParameter(ConfigKey.MIME_TYPE.getKeyValue());
        if (requestMimeType != null) {
            return requestMimeType;
        }
        return configMimeType;
    }


	public HomePageConfig loadConfigFor(Identity identity) {
		String userName = identity.getName();
		HomePageConfig retVal = null;
		File configFile = getConfigFile(userName);
		if (!configFile.exists()) {
			// config file does not exist! create one, init the defaults, save it.
			retVal = loadAndSaveDefaults(identity);
		} else {
			// file exists, load it with XStream, resolve version
			try {
				Object tmp = homeConfigXStream.fromXML(configFile);
				if (tmp instanceof HomePageConfig) {
					retVal = (HomePageConfig)tmp;
					if(retVal.resolveVersionIssues()) {
						saveConfigTo(identity, retVal);
					}
				}
			} catch (Exception e) {
				log.error("Error while loading homepage config from path::" + configFile.getAbsolutePath() + ", fallback to default configuration",
						e);
				FileUtils.deleteFile(configFile);
				retVal = loadAndSaveDefaults(identity);
				// show message to user
			}
		}
		return retVal;
	}


    private static TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
            return new java.security.cert.X509Certificate[] {};
        }

        public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) {
            //No need to implement.
        }

        public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) {
            //No need to implement.
        }
    } };


    public static int getStatusCode(HttpURLConnection conn) {
        try {
            return conn.getResponseCode();
        } catch (IOException e) {
            throw ErrorUtil
                    .createCommandException("connection to the remote repository host failed: " + e.getMessage());
        }
    }


    public ResponseEntity<Resource> download(@PathVariable String key) {
        LitemallStorage litemallStorage = litemallStorageService.findByKey(key);
        if (key == null) {
            ResponseEntity.notFound();
        }
        String type = litemallStorage.getType();
        MediaType mediaType = MediaType.parseMediaType(type);

        Resource file = storageService.loadAsResource(key);
        if (file == null) {
            ResponseEntity.notFound();
        }
        return ResponseEntity.ok().contentType(mediaType).header(HttpHeaders.CONTENT_DISPOSITION,
                "attachment; filename=\"" + file.getFilename() + "\"").body(file);
    }


    void routingResult() throws URISyntaxException {
        final RoutingResultBuilder builder = RoutingResult.builder();
        final RoutingResult routingResult = builder.path("/foo")
                                                   .query("bar=baz")
                                                   .rawParam("qux", "quux")
                                                   .negotiatedResponseMediaType(MediaType.JSON_UTF_8)
                                                   .build();
        assertThat(routingResult.isPresent()).isTrue();
        assertThat(routingResult.path()).isEqualTo("/foo");
        assertThat(routingResult.query()).isEqualTo("bar=baz");
        assertThat(routingResult.pathParams()).containsOnly(new SimpleEntry<>("qux", "quux"));
        assertThat(routingResult.negotiatedResponseMediaType()).isSameAs(MediaType.JSON_UTF_8);
    }


	public CommandExecutionResult createRobustConcise(String code, String full, TimingStyle type, boolean compact) {
		final Player player = new PlayerRobustConcise(type, full, getSkinParam(), ruler, compactByDefault || compact);
		players.put(code, player);
		lastPlayer = player;
		return CommandExecutionResult.ok();
	}


    public BCXMSSMTPrivateKey(PrivateKeyInfo keyInfo)
        throws IOException
    {
        XMSSMTKeyParams keyParams = XMSSMTKeyParams.getInstance(keyInfo.getPrivateKeyAlgorithm().getParameters());
        this.treeDigest = keyParams.getTreeDigest().getAlgorithm();

        XMSSPrivateKey xmssMtPrivateKey = XMSSPrivateKey.getInstance(keyInfo.parsePrivateKey());

        try
        {
            XMSSMTPrivateKeyParameters.Builder keyBuilder = new XMSSMTPrivateKeyParameters
                .Builder(new XMSSMTParameters(keyParams.getHeight(), keyParams.getLayers(), DigestUtil.getDigest(treeDigest)))
                .withIndex(xmssMtPrivateKey.getIndex())
                .withSecretKeySeed(xmssMtPrivateKey.getSecretKeySeed())
                .withSecretKeyPRF(xmssMtPrivateKey.getSecretKeyPRF())
                .withPublicSeed(xmssMtPrivateKey.getPublicSeed())
                .withRoot(xmssMtPrivateKey.getRoot());

            if (xmssMtPrivateKey.getBdsState() != null)
            {
                keyBuilder.withBDSState((BDSStateMap)XMSSUtil.deserialize(xmssMtPrivateKey.getBdsState()));
            }

            this.keyParams = keyBuilder.build();
        }
        catch (ClassNotFoundException e)
        {
            throw new IOException("ClassNotFoundException processing BDS state: " + e.getMessage());
        }
    }


    public AuthenticationInfo loadAuthenticationInfo(JSONWebToken token) {
        Key key = getJWTKey();
        Jwt jwt;
        try {
            jwt = Jwts.parser().setSigningKey(key).parse(token.getPrincipal());
        } catch (JwtException e) {
            throw new AuthenticationException(e);
        }
        String credentials = legacyHashing ? token.getCredentials() : encryptPassword(token.getCredentials());
        Object principal = extractPrincipalFromWebToken(jwt);
        return new SimpleAuthenticationInfo(principal, credentials, getName());
    }


	public static final void toStream(Binder binder, ZipOutputStream zout)
	throws IOException {
		try(OutputStream out=new ShieldOutputStream(zout)) {
			myStream.toXML(binder, out);
		} catch (Exception e) {
			log.error("Cannot export this map: " + binder, e);
		}
	}


    public String getStringParameterSQL(String param) {
        return "'" + param + "'";
    }


	public Object getResourceDataForKey(String key) {
		Object data = null;
		String dataString = null;
		Matcher matcher = DATA_SEPARATOR_PATTERN.matcher(key);
		if (matcher.find()) {
			if (log.isDebugEnabled()) {
				log.debug(Messages.getMessage(
						Messages.RESTORE_DATA_FROM_RESOURCE_URI_INFO, key,
						dataString));
			}
			int dataStart = matcher.end();
			dataString = key.substring(dataStart);
			byte[] objectArray = null;
			byte[] dataArray;
			try {
				dataArray = dataString.getBytes("ISO-8859-1");
				objectArray = decrypt(dataArray);
			} catch (UnsupportedEncodingException e1) {
				// default encoding always presented.
			}
			if ("B".equals(matcher.group(1))) {
				data = objectArray;
			} else {
				try {
					ObjectInputStream in = new ObjectInputStream(
							new ByteArrayInputStream(objectArray));
					data = in.readObject();
				} catch (StreamCorruptedException e) {
					log.error(Messages
							.getMessage(Messages.STREAM_CORRUPTED_ERROR), e);
				} catch (IOException e) {
					log.error(Messages
							.getMessage(Messages.DESERIALIZE_DATA_INPUT_ERROR),
							e);
				} catch (ClassNotFoundException e) {
					log
							.error(
									Messages
											.getMessage(Messages.DATA_CLASS_NOT_FOUND_ERROR),
									e);
				}
			}
		}

		return data;
	}


	public static boolean isAbsolute(String url)
	{
		if (url.startsWith("//"))  // //www.domain.com/start
		{
			return true;
		}

		if (url.startsWith("/")) // /somePage.html
		{
			return false;
		}

		boolean result = false;

		try
		{
			URI uri = new URI(url);
			result = uri.isAbsolute();
		}
		catch (URISyntaxException e) {} //Ignore

		return result;
	}


	public ChangeState(TimeTick when, String comment, Colors colors, String... states) {
		if (states.length == 0) {
			throw new IllegalArgumentException();
		}
		this.when = when;
		this.states = states;
		this.comment = comment;
		this.colors = colors;
	}


	public SymbolContext getContext(ISkinParam skinParam, Style style) {
		return new SymbolContext(getBackColor(skinParam, style), getLineColor(skinParam, style))
				.withStroke(new UStroke(1.5));
	}


	public Controller execute(FolderComponent folderComponent, UserRequest ureq, WindowControl wControl, Translator trans) {
		setTranslator(trans);
		currentContainer = folderComponent.getCurrentContainer();
		if (currentContainer.canWrite() != VFSConstants.YES) {
			throw new AssertException("Cannot write to current folder.");
		}

		status = FolderCommandHelper.sanityCheck(wControl, folderComponent);
		if(status == FolderCommandStatus.STATUS_FAILED) {
			return null;
		}

		selection = new FileSelection(ureq, folderComponent.getCurrentContainerPath());
		status = FolderCommandHelper.sanityCheck3(wControl, folderComponent, selection);
		if(status == FolderCommandStatus.STATUS_FAILED) {
			return null;
		}

		if(selection.getFiles().isEmpty()) {
			status = FolderCommandStatus.STATUS_FAILED;
			wControl.setWarning(trans.translate("warning.file.selection.empty"));
			return null;
		}

		initForm(ureq);
		return this;
	}


	public PlayerRobustConcise(TimingStyle type, String full, ISkinParam skinParam, TimingRuler ruler,
			boolean compact) {
		super(full, skinParam, ruler, compact);
		this.type = type;
		this.suggestedHeight = 0;
	}


  private <T> byte[] marshallToBytes(JAXBElement<T> object, Class<T> type) throws SAMLException {
    try {
      JAXBContext context = JAXBContext.newInstance(type);
      Marshaller marshaller = context.createMarshaller();
      ByteArrayOutputStream baos = new ByteArrayOutputStream();
      marshaller.marshal(object, baos);
      return baos.toByteArray();
    } catch (JAXBException e) {
      throw new SAMLException("Unable to marshallRequest JAXB SAML object to bytes.", e);
    }
  }


    public static String getRealIp(HttpServletRequest request) {
        //bae env
        if (ZrLogUtil.isBae() && request.getHeader("clientip") != null) {
            return request.getHeader("clientip");
        }
        String ip = request.getHeader("X-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("X-Real-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }


    public String[] getCommandline()
    {
        final String[] args = getArguments();
        String executable = getExecutable();

        if ( executable == null )
        {
            return args;
        }
        final String[] result = new String[args.length + 1];
        result[0] = executable;
        System.arraycopy( args, 0, result, 1, args.length );
        return result;
    }


    public void testFileRegionCountLargerThenFile(ServerBootstrap sb, Bootstrap cb) throws Throwable {
        File file = File.createTempFile("netty-", ".tmp");
        file.deleteOnExit();

        final FileOutputStream out = new FileOutputStream(file);
        out.write(data);
        out.close();

        sb.childHandler(new SimpleChannelInboundHandler<ByteBuf>() {
            @Override
            protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) {
                // Just drop the message.
            }
        });
        cb.handler(new ChannelInboundHandlerAdapter());

        Channel sc = sb.bind().sync().channel();
        Channel cc = cb.connect(sc.localAddress()).sync().channel();

        // Request file region which is bigger then the underlying file.
        FileRegion region = new DefaultFileRegion(
                new RandomAccessFile(file, "r").getChannel(), 0, data.length + 1024);

        assertThat(cc.writeAndFlush(region).await().cause(), CoreMatchers.<Throwable>instanceOf(IOException.class));
        cc.close().sync();
        sc.close().sync();
    }


    public void setValidation(boolean validation) {
        this.validating = validation;
    }


	public Media createMedia(String title, String description, Object mediaObject, String businessPath, Identity author) {
		Media media = null;
		if (mediaObject instanceof EfficiencyStatement) {
			EfficiencyStatement statement = (EfficiencyStatement) mediaObject;
			String xml = myXStream.toXML(statement);
			media = mediaDao.createMedia(title, description, xml, EFF_MEDIA, businessPath, null, 90, author);
			ThreadLocalUserActivityLogger.log(PortfolioLoggingAction.PORTFOLIO_MEDIA_ADDED, getClass(),
					LoggingResourceable.wrap(media));
		}
		return media;
	}


	public int decryptWithAd(byte[] ad, byte[] ciphertext,
			int ciphertextOffset, byte[] plaintext, int plaintextOffset,
			int length) throws ShortBufferException, BadPaddingException {
		int space;
		if (ciphertextOffset > ciphertext.length)
			space = 0;
		else
			space = ciphertext.length - ciphertextOffset;
		if (length > space)
			throw new ShortBufferException();
		if (plaintextOffset > plaintext.length)
			space = 0;
		else
			space = plaintext.length - plaintextOffset;
		if (!haskey) {
			// The key is not set yet - return the ciphertext as-is.
			if (length > space)
				throw new ShortBufferException();
			if (plaintext != ciphertext || plaintextOffset != ciphertextOffset)
				System.arraycopy(ciphertext, ciphertextOffset, plaintext, plaintextOffset, length);
			return length;
		}
		if (length < 16)
			Noise.throwBadTagException();
		int dataLen = length - 16;
		if (dataLen > space)
			throw new ShortBufferException();
		setup(ad);
		ghash.update(ciphertext, ciphertextOffset, dataLen);
		ghash.pad(ad != null ? ad.length : 0, dataLen);
		ghash.finish(enciv, 0, 16);
		int temp = 0;
		for (int index = 0; index < 16; ++index)
			temp |= (hashKey[index] ^ enciv[index] ^ ciphertext[ciphertextOffset + dataLen + index]);
		if ((temp & 0xFF) != 0)
			Noise.throwBadTagException();
		encryptCTR(ciphertext, ciphertextOffset, plaintext, plaintextOffset, dataLen);
		return dataLen;
	}


    void testDecodePath() throws Exception {
        // Fast path
        final String pathThatDoesNotNeedDecode = "/foo_bar_baz";
        assertThat(decodePath(pathThatDoesNotNeedDecode)).isSameAs(pathThatDoesNotNeedDecode);

        // Slow path
        assertThat(decodePath("/foo%20bar\u007fbaz")).isEqualTo("/foo bar\u007fbaz");
        assertThat(decodePath("/%C2%A2")).isEqualTo("/¢"); // Valid UTF-8 sequence
        assertThat(decodePath("/%20\u0080")).isEqualTo("/ �"); // Unallowed character
        assertThat(decodePath("/%")).isEqualTo("/�"); // No digit
        assertThat(decodePath("/%1")).isEqualTo("/�"); // Only a single digit
        assertThat(decodePath("/%G0")).isEqualTo("/�"); // First digit is not hex.
        assertThat(decodePath("/%0G")).isEqualTo("/�"); // Second digit is not hex.
        assertThat(decodePath("/%C3%28")).isEqualTo("/�("); // Invalid UTF-8 sequence
    }


	protected StyleSignatureBasic getStyleSignature() {
		return StyleSignatureBasic.of(SName.root, SName.element, SName.timingDiagram, SName.binary);
	}


	public void export(Media media, ManifestBuilder manifest, File mediaArchiveDirectory, Locale locale) {
		EfficiencyStatement statement = null;
		if(StringHelper.containsNonWhitespace(media.getContent())) {
			try {
				statement = (EfficiencyStatement)myXStream.fromXML(media.getContent());
			} catch (Exception e) {
				log.error("Cannot load efficiency statement from artefact", e);
			}
		}
		if(statement != null) {
			List<Map<String,Object>> assessmentNodes = statement.getAssessmentNodes();
			List<AssessmentNodeData> assessmentNodeList = AssessmentHelper.assessmentNodeDataMapToList(assessmentNodes);
			SyntheticUserRequest ureq = new SyntheticUserRequest(media.getAuthor(), locale);
			IdentityAssessmentOverviewController details = new IdentityAssessmentOverviewController(ureq, new WindowControlMocker(), assessmentNodeList);
			super.exportContent(media, details.getInitialComponent(), null, mediaArchiveDirectory, locale);
		}
	}


    public static void execute(String url, String proxyHost, int proxyPort, String proxyUsername, String proxyPassword,
            String accessToken, String orgName, String moduleName, String version, Path baloPath) {
        initializeSsl();
        HttpURLConnection conn = createHttpUrlConnection(convertToUrl(url), proxyHost, proxyPort, proxyUsername,
                proxyPassword);
        conn.setInstanceFollowRedirects(false);
        setRequestMethod(conn, Utils.RequestMethod.POST);

        // Set headers
        conn.setRequestProperty(HttpHeaders.AUTHORIZATION, "Bearer " + accessToken);
        conn.setRequestProperty(PUSH_ORGANIZATION, orgName);
        conn.setRequestProperty(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_OCTET_STREAM);

        conn.setDoOutput(true);
        conn.setChunkedStreamingMode(BUFFER_SIZE);

        try (DataOutputStream outputStream = new DataOutputStream(conn.getOutputStream())) {
            // Send balo content by 1 kb chunks
            byte[] buffer = new byte[BUFFER_SIZE];
            int count;
            try (ProgressBar progressBar = new ProgressBar(
                    orgName + "/" + moduleName + ":" + version + " [project repo -> central]",
                    getTotalFileSizeInKB(baloPath), 1000, outStream, ProgressBarStyle.ASCII, " KB", 1);
                    FileInputStream fis = new FileInputStream(baloPath.toFile())) {
                while ((count = fis.read(buffer)) > 0) {
                    outputStream.write(buffer, 0, count);
                    outputStream.flush();
                    progressBar.stepBy((long) NO_OF_BYTES);
                }
            }
        } catch (IOException e) {
            throw ErrorUtil.createCommandException("error occurred while uploading balo to central: " + e.getMessage());
        }

        handleResponse(conn, orgName, moduleName, version);
        Authenticator.setDefault(null);
    }


    public void addHandler(String path, ElementHandler handler) {
        getDispatchHandler().addHandler(path, handler);
    }


    DefaultResetPasswordRequestResponse(UserReference reference, InternetAddress userEmail, String verificationCode)
    {
        this.userReference = reference;
        this.userEmail = userEmail;
        this.verificationCode = verificationCode;
    }


	public int encryptWithAd(byte[] ad, byte[] plaintext, int plaintextOffset,
			byte[] ciphertext, int ciphertextOffset, int length)
			throws ShortBufferException {
		int space;
		if (ciphertextOffset > ciphertext.length)
			space = 0;
		else
			space = ciphertext.length - ciphertextOffset;
		if (keySpec == null) {
			// The key is not set yet - return the plaintext as-is.
			if (length > space)
				throw new ShortBufferException();
			if (plaintext != ciphertext || plaintextOffset != ciphertextOffset)
				System.arraycopy(plaintext, plaintextOffset, ciphertext, ciphertextOffset, length);
			return length;
		}
		if (space < 16 || length > (space - 16))
			throw new ShortBufferException();
		try {
			setup(ad);
			int result = cipher.update(plaintext, plaintextOffset, length, ciphertext, ciphertextOffset);
			cipher.doFinal(ciphertext, ciphertextOffset + result);
		} catch (InvalidKeyException e) {
			// Shouldn't happen.
			throw new IllegalStateException(e);
		} catch (InvalidAlgorithmParameterException e) {
			// Shouldn't happen.
			throw new IllegalStateException(e);
		} catch (IllegalBlockSizeException e) {
			// Shouldn't happen.
			throw new IllegalStateException(e);
		} catch (BadPaddingException e) {
			// Shouldn't happen.
			throw new IllegalStateException(e);
		}
		ghash.update(ciphertext, ciphertextOffset, length);
		ghash.pad(ad != null ? ad.length : 0, length);
		ghash.finish(ciphertext, ciphertextOffset + length, 16);
		for (int index = 0; index < 16; ++index)
			ciphertext[ciphertextOffset + length + index] ^= hashKey[index];
		return length + 16;
	}


	public boolean archiveNodeData(Locale locale, ICourse course, ArchiveOptions options,
			ZipOutputStream exportStream, String archivePath, String charset) {
		String filename = "checklist_"
				+ StringHelper.transformDisplayNameToFileSystemName(getShortName())
				+ "_" + Formatter.formatDatetimeFilesystemSave(new Date(System.currentTimeMillis()));
		filename = ZipUtil.concat(archivePath, filename);

		Checklist checklist = loadOrCreateChecklist(course.getCourseEnvironment().getCoursePropertyManager());
		String exportContent = XStreamHelper.createXStreamInstance().toXML(checklist);
		try {
			exportStream.putNextEntry(new ZipEntry(filename));
			IOUtils.write(exportContent, exportStream, "UTF-8");
			exportStream.closeEntry();
		} catch (IOException e) {
			log.error("", e);
		}
		return true;
	}


	public boolean isMetadataFileValid(OLATResource videoResource) {
		VFSContainer baseContainer = FileResourceManager.getInstance().getFileResourceRootImpl(videoResource);
		VFSLeaf metaDataFile = (VFSLeaf) baseContainer.resolve(FILENAME_VIDEO_METADATA_XML);
		try {
			VideoMetadata meta = (VideoMetadata) XStreamHelper.readObject(XStreamHelper.createXStreamInstance(), metaDataFile);
			return meta != null;
		} catch (Exception e) {
			return false;
		}
	}


    public static String getAttachedFilePath(String inputStudyOid) {
    	// Using a standard library to validate/Sanitize user inputs which will be used in path expression to prevent from path traversal
    	String studyOid =  FilenameUtils.getName(inputStudyOid);
        String attachedFilePath = CoreResources.getField("attached_file_location");
        if (attachedFilePath == null || attachedFilePath.length() <= 0) {
            attachedFilePath = CoreResources.getField("filePath") + "attached_files" + File.separator + studyOid + File.separator;
        } else {
            attachedFilePath += studyOid + File.separator;
        }
        return attachedFilePath;
    }


	public Controller execute(FolderComponent fc, UserRequest ureq, WindowControl windowControl, Translator trans) {
		this.folderComponent = fc;
		this.translator = trans;
		this.fileSelection = new FileSelection(ureq, fc.getCurrentContainerPath());

		VelocityContainer main = new VelocityContainer("mc", VELOCITY_ROOT + "/movecopy.html", translator, this);
		main.contextPut("fileselection", fileSelection);

		//check if command is executed on a file list containing invalid filenames or paths
		if(!fileSelection.getInvalidFileNames().isEmpty()) {
			main.contextPut("invalidFileNames", fileSelection.getInvalidFileNames());
		}

		selTree = new MenuTree(null, "seltree", this);
		FolderTreeModel ftm = new FolderTreeModel(ureq.getLocale(), fc.getRootContainer(),
				true, false, true, fc.getRootContainer().canWrite() == VFSConstants.YES, new EditableFilter());
		selTree.setTreeModel(ftm);
		selectButton = LinkFactory.createButton(move ? "move" : "copy", main, this);
		cancelButton = LinkFactory.createButton("cancel", main, this);

		main.put("seltree", selTree);
		if (move) {
			main.contextPut("move", Boolean.TRUE);
		}

		setInitialComponent(main);
		return this;
	}


    private void handle(ServletRequestHandler pReqHandler,HttpServletRequest pReq, HttpServletResponse pResp) throws IOException {
        JSONAware json = null;
        try {
            // Check access policy
            requestHandler.checkAccess(allowDnsReverseLookup ? pReq.getRemoteHost() : null,
                                       pReq.getRemoteAddr(),
                                       getOriginOrReferer(pReq));

            // Remember the agent URL upon the first request. Needed for discovery
            updateAgentDetailsIfNeeded(pReq);

            // Dispatch for the proper HTTP request method
            json = handleSecurely(pReqHandler, pReq, pResp);
        } catch (Throwable exp) {
            json = requestHandler.handleThrowable(
                    exp instanceof RuntimeMBeanException ? ((RuntimeMBeanException) exp).getTargetException() : exp);
        } finally {
            setCorsHeader(pReq, pResp);

            if (json == null) {
                json = requestHandler.handleThrowable(new Exception("Internal error while handling an exception"));
            }

            sendResponse(pResp, pReq, json);
        }
    }


	public void testSelectByOperations() {

		JWKSelector selector = new JWKSelector(new JWKMatcher.Builder().keyOperations(KeyOperation.SIGN, KeyOperation.VERIFY).build());

		List<JWK> keyList = new ArrayList<>();
		keyList.add(new RSAKey.Builder(new Base64URL("n"), new Base64URL("e")).keyID("1")
			.keyOperations(new HashSet<>(Arrays.asList(KeyOperation.SIGN, KeyOperation.VERIFY))).build());
		keyList.add(new ECKey.Builder(ECKey.Curve.P_256, new Base64URL("x"), new Base64URL("y")).keyID("2").build());

		JWKSet jwkSet = new JWKSet(keyList);

		List<JWK> matches = selector.select(jwkSet);

		RSAKey key1 = (RSAKey)matches.get(0);
		assertEquals(KeyType.RSA, key1.getKeyType());
		assertEquals("1", key1.getKeyID());

		assertEquals(1, matches.size());
	}


    static void setProperty(SchemaFactory schemaFactory, String propertyName) throws SAXException {
        try {
            schemaFactory.setProperty(propertyName, "");
        } catch (SAXException e) {
            if (Boolean.getBoolean(SYSTEM_PROPERTY_IGNORE_XXE_PROTECTION_FAILURES)) {
                LOGGER.warning("Enabling XXE protection failed. The property " + propertyName
                        + " is not supported by the SchemaFactory. The " + SYSTEM_PROPERTY_IGNORE_XXE_PROTECTION_FAILURES
                        + " system property is used so the XML processing continues in the UNSECURE mode"
                        + " with XXE protection disabled!!!");
            } else {
                LOGGER.severe("Enabling XXE protection failed. The property " + propertyName
                        + " is not supported by the SchemaFactory. This usually mean an outdated XML processor"
                        + " is present on the classpath (e.g. Xerces, Xalan). If you are not able to resolve the issue by"
                        + " fixing the classpath, the " + SYSTEM_PROPERTY_IGNORE_XXE_PROTECTION_FAILURES
                        + " system property can be used to disable XML External Entity protections."
                        + " We don't recommend disabling the XXE as such the XML processor configuration is unsecure!!!", e);
                throw e;
            }
        }
    }


    public Document read(String systemId) throws DocumentException {
        InputSource source = new InputSource(systemId);
        if (this.encoding != null) {
            source.setEncoding(this.encoding);
        }

        return read(source);
    }


    private void onopen() {
        logger.fine("open");

        this.cleanup();

        this.readyState = ReadyState.OPEN;
        this.emit(EVENT_OPEN);

        final io.socket.engineio.client.Socket socket = this.engine;
        this.subs.add(On.on(socket, Engine.EVENT_DATA, new Listener() {
            @Override
            public void call(Object... objects) {
                Object data = objects[0];
                if (data instanceof String) {
                    Manager.this.ondata((String)data);
                } else if (data instanceof byte[]) {
                    Manager.this.ondata((byte[])data);
                }
            }
        }));
        this.subs.add(On.on(socket, Engine.EVENT_ERROR, new Listener() {
            @Override
            public void call(Object... objects) {
                Manager.this.onerror((Exception)objects[0]);
            }
        }));
        this.subs.add(On.on(socket, Engine.EVENT_CLOSE, new Listener() {
            @Override
            public void call(Object... objects) {
                Manager.this.onclose((String)objects[0]);
            }
        }));
        this.decoder.onDecoded(new Parser.Decoder.Callback() {
            @Override
            public void call (Packet packet) {
                Manager.this.ondecoded(packet);
            }
        });
    }


    public static DomainSocketAddress newSocketAddress() {
        try {
            File file;
            do {
                file = File.createTempFile("NETTY", "UDS");
                if (!file.delete()) {
                    throw new IOException("failed to delete: " + file);
                }
            } while (file.getAbsolutePath().length() > 128);
            return new DomainSocketAddress(file);
        } catch (IOException e) {
            throw new IllegalStateException(e);
        }
    }


    private boolean processStyleTag(Element ele, Node parentNode) {
        /*
         * Invoke the css parser on this element.
         */
        CssScanner styleScanner = new CssScanner(policy, messages, policy.isEmbedStyleSheets());

        try {
            Node firstChild = ele.getFirstChild();
            if (firstChild != null) {

                String toScan = firstChild.getNodeValue();
                CleanResults cr = styleScanner.scanStyleSheet(toScan, policy.getMaxInputSize());
                errorMessages.addAll(cr.getErrorMessages());

                /*
                 * If IE gets an empty style tag, i.e. <style/> it will
                 * break all CSS on the page. I wish I was kidding. So,
                 * if after validation no CSS properties are left, we
                 * would normally be left with an empty style tag and
                 * break all CSS. To prevent that, we have this check.
                 */

                final String cleanHTML = cr.getCleanHTML();

                if (cleanHTML == null || cleanHTML.equals("")) {
                    firstChild.setNodeValue("/* */");
                } else {
                    firstChild.setNodeValue(cleanHTML);
                }
            }

        } catch (DOMException | ScanException | ParseException | NumberFormatException e) {

            /*
             * ParseException shouldn't be possible anymore, but we'll leave it
             * here because I (Arshan) am hilariously dumb sometimes.
             * Batik can throw NumberFormatExceptions (see bug #48).
             */

            addError(ErrorMessageUtil.ERROR_CSS_TAG_MALFORMED, new Object[]{HTMLEntityEncoder.htmlEntityEncode(ele.getFirstChild().getNodeValue())});
            parentNode.removeChild(ele);
            return true;
        }
        return false;
    }


    protected Map<String, Serializable> getPrincipal(Jwt jwt) {
        Map<String, Serializable> principal = new HashMap<>();
        principal.put("jwt", (Serializable) jwt.getBody());
        return principal;
    }


    private ByteArrayOutputStream initRequestResponseMocks(String callback,Runnable requestSetup,Runnable responseSetup) throws IOException {
        request = createMock(HttpServletRequest.class);
        response = createMock(HttpServletResponse.class);
        setNoCacheHeaders(response);

        expect(request.getParameter(ConfigKey.CALLBACK.getKeyValue())).andReturn(callback);
        requestSetup.run();
        responseSetup.run();

        class MyServletOutputStream extends ServletOutputStream {
            ByteArrayOutputStream baos;
            public void write(int b) throws IOException {
                baos.write(b);
            }

            public void setBaos(ByteArrayOutputStream baos){
                this.baos = baos;
            }
        }
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        MyServletOutputStream sos = new MyServletOutputStream();
        sos.setBaos(baos);
        expect(response.getOutputStream()).andReturn(sos);

        return baos;
    }


	private String clean(String svg) {
		svg = svg.toLowerCase().replaceAll("\\s", "");
		if (svg.contains("<script>"))
			return EMPTY_SVG;
		if (svg.contains("</script>"))
			return EMPTY_SVG;
		if (svg.contains("<foreignobject"))
			return EMPTY_SVG;
		if (svg.contains("</foreignobject>"))
			return EMPTY_SVG;
		return svg;
	}


    public URL createURL(String spaces, String name, String queryString, String anchor, String wikiId,
        XWikiContext context, FilesystemExportContext exportContext) throws Exception
    {
        // Check if the current user has the right to view the SX file. We do this since this is what would happen
        // in XE when a SX action is called (check done in XWikiAction).
        // Note that we cannot just open an HTTP connection to the SX action here since we wouldn't be authenticated...
        // Thus we have to simulate the same behavior as the SX action...

        List<String> spaceNames = this.legacySpaceResolve.resolve(spaces);
        DocumentReference sxDocumentReference = new DocumentReference(wikiId, spaceNames, name);
        this.authorizationManager.checkAccess(Right.VIEW, sxDocumentReference);

        // Set the SX document as the current document in the XWiki Context since unfortunately the SxSource code
        // uses the current document in the context instead of accepting it as a parameter...
        XWikiDocument sxDocument = context.getWiki().getDocument(sxDocumentReference, context);

        Map<String, Object> backup = new HashMap<>();
        XWikiDocument.backupContext(backup, context);
        try {
            sxDocument.setAsContextDoc(context);
            return processSx(spaceNames, name, queryString, context, exportContext);
        } finally {
            XWikiDocument.restoreContext(backup, context);
        }
    }


    private static File newFile() throws IOException {
        File file = File.createTempFile("netty-", ".tmp");
        file.deleteOnExit();

        final FileOutputStream out = new FileOutputStream(file);
        out.write(data);
        out.close();
        return file;
    }


	public int encryptWithAd(byte[] ad, byte[] plaintext, int plaintextOffset,
			byte[] ciphertext, int ciphertextOffset, int length) throws ShortBufferException {
		int space;
		if (ciphertextOffset > ciphertext.length)
			space = 0;
		else
			space = ciphertext.length - ciphertextOffset;
		if (!haskey) {
			// The key is not set yet - return the plaintext as-is.
			if (length > space)
				throw new ShortBufferException();
			if (plaintext != ciphertext || plaintextOffset != ciphertextOffset)
				System.arraycopy(plaintext, plaintextOffset, ciphertext, ciphertextOffset, length);
			return length;
		}
		if (space < 16 || length > (space - 16))
			throw new ShortBufferException();
		setup(ad);
		encrypt(plaintext, plaintextOffset, ciphertext, ciphertextOffset, length);
		poly.update(ciphertext, ciphertextOffset, length);
		finish(ad, length);
		System.arraycopy(polyKey, 0, ciphertext, ciphertextOffset + length, 16);
		return length + 16;
	}


    private static void testInvalidHeaders0(String requestStr) {
        EmbeddedChannel channel = new EmbeddedChannel(new HttpRequestDecoder());
        assertTrue(channel.writeInbound(Unpooled.copiedBuffer(requestStr, CharsetUtil.US_ASCII)));
        HttpRequest request = channel.readInbound();
        assertTrue(request.decoderResult().isFailure());
        assertTrue(request.decoderResult().cause() instanceof IllegalArgumentException);
        assertFalse(channel.finish());
    }


	public static Object readObject(XStream xStream, String xml) {
		try(InputStream is = new ByteArrayInputStream(xml.getBytes(ENCODING))) {
			return readObject(xStream, is);
		} catch (Exception e) {
			throw new OLATRuntimeException(XStreamHelper.class,
					"could not read Object from string: " + xml, e);
		}
	}


    protected XMLReader installXMLFilter(XMLReader reader) {
        XMLFilter filter = getXMLFilter();

        if (filter != null) {
            // find the root XMLFilter
            XMLFilter root = filter;

            while (true) {
                XMLReader parent = root.getParent();

                if (parent instanceof XMLFilter) {
                    root = (XMLFilter) parent;
                } else {
                    break;
                }
            }

            root.setParent(reader);

            return filter;
        }

        return reader;
    }


    public PropertiesRequest getRequestedFields( InputStream in ) {
		final Set<QName> set = new LinkedHashSet<QName>();
        try {
            ByteArrayOutputStream bout = new ByteArrayOutputStream();
            StreamUtils.readTo( in, bout, false, true );
            byte[] arr = bout.toByteArray();
            if( arr.length > 1 ) {
                ByteArrayInputStream bin = new ByteArrayInputStream( arr );
                XMLReader reader = XMLReaderFactory.createXMLReader();
				reader.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
                PropFindSaxHandler handler = new PropFindSaxHandler();
                reader.setContentHandler( handler );
                try {
                    reader.parse( new InputSource( bin ) );
                    if( handler.isAllProp() ) {
                        return new PropertiesRequest();
                    } else {
                        set.addAll( handler.getAttributes().keySet() );
                    }
                } catch( IOException e ) {
                    log.warn( "exception parsing request body", e );
                    // ignore
                } catch( SAXException e ) {
                    log.warn( "exception parsing request body", e );
                    // ignore
                }
            }
        } catch( Exception ex ) {
			// There's a report of an exception being thrown here by IT Hit Webdav client
			// Perhaps we can just log the error and return an empty set. Usually this
			// class is wrapped by the MsPropFindRequestFieldParser which will use a default
			// set of properties if this returns an empty set
			log.warn("Exception parsing PROPFIND request fields. Returning empty property set", ex);
            //throw new RuntimeException( ex );
        }
		return PropertiesRequest.toProperties(set);
    }


    public void setEncoding(String encoding) {
        this.encoding = encoding;
    }


    private boolean extract(ArrayList<String> errors, URL source, File target) {
        FileOutputStream os = null;
        InputStream is = null;
        boolean extracting = false;
        try {
            if (!target.exists() || isStale(source, target) ) {
                is = source.openStream();
                if (is != null) {
                    byte[] buffer = new byte[4096];
                    os = new FileOutputStream(target);
                    extracting = true;
                    int read;
                    while ((read = is.read(buffer)) != -1) {
                        os.write(buffer, 0, read);
                    }
                    os.close();
                    is.close();
                    chmod("755", target);
                }
            }
        } catch (Throwable e) {
            try {
                if (os != null)
                    os.close();
            } catch (IOException e1) {
            }
            try {
                if (is != null)
                    is.close();
            } catch (IOException e1) {
            }
            if (extracting && target.exists())
                target.delete();
            errors.add(e.getMessage());
            return false;
        }
        return true;
    }


    private Optional<Map<String, Object>> readPropertiesFromLoader(String fileName, String filePath, PropertySourceLoader propertySourceLoader) throws ConfigurationException {
        ResourceResolver resourceResolver = new ResourceResolver();
        Optional<ResourceLoader> resourceLoader = resourceResolver.getSupportingLoader(filePath);
        ResourceLoader loader = resourceLoader.orElse(FileSystemResourceLoader.defaultLoader());
        try {
            Optional<InputStream> inputStream = loader.getResourceAsStream(filePath);
            if (inputStream.isPresent()) {
                return Optional.of(propertySourceLoader.read(fileName, inputStream.get()));
            } else {
                throw new ConfigurationException("Failed to read configuration file: " + filePath);
            }
        } catch (IOException e) {
            throw new ConfigurationException("Unsupported properties file: " + fileName);
        }
    }


    public void testGetShellCommandLineBash_WithSingleQuotedArg()
        throws Exception
    {
        Commandline cmd = new Commandline( new BourneShell() );
        cmd.setExecutable( "/bin/echo" );
        cmd.addArguments( new String[] {
            "\'hello world\'"
        } );

        String[] shellCommandline = cmd.getShellCommandline();

        assertEquals( "Command line size", 3, shellCommandline.length );

        assertEquals( "/bin/sh", shellCommandline[0] );
        assertEquals( "-c", shellCommandline[1] );
        String expectedShellCmd = "/bin/echo \'hello world\'";
        if ( Os.isFamily( Os.FAMILY_WINDOWS ) )
        {
            expectedShellCmd = "\\bin\\echo \'hello world\'";
        }
        assertEquals( expectedShellCmd, shellCommandline[2] );
    }


    public String list(Model model, // TODO model should no longer be injected
                       @RequestParam(required = false, defaultValue = "FILENAME") SortBy sortBy,
                       @RequestParam(required = false, defaultValue = "false") boolean desc,
                       @RequestParam(required = false) String base) throws IOException, TemplateException {
        securityCheck(base);

        Path currentFolder = loggingPath(base);

        List<FileEntry> files = getFileProvider(currentFolder).getFileEntries(currentFolder);
        List<FileEntry> sortedFiles = sortFiles(files, sortBy, desc);

        model.addAttribute("sortBy", sortBy);
        model.addAttribute("desc", desc);
        model.addAttribute("files", sortedFiles);
        model.addAttribute("currentFolder", currentFolder.toAbsolutePath().toString());
        model.addAttribute("base", base != null ? URLEncoder.encode(base, "UTF-8") : "");
        model.addAttribute("parent", getParent(currentFolder));
        model.addAttribute("stylesheets", stylesheets);

        return FreeMarkerTemplateUtils.processTemplateIntoString(freemarkerConfig.getTemplate("logview.ftl"), model);
    }


    protected static String unifyQuotes( String path )
    {
        if ( path == null )
        {
            return null;
        }

        if ( path.indexOf( " " ) == -1 && path.indexOf( "'" ) != -1 && path.indexOf( "\"" ) == -1 )
        {
            return StringUtils.escape( path );
        }

        return StringUtils.quoteAndEscape( path, '\"', BASH_QUOTING_TRIGGER_CHARS );
    }


        public int getPosition()
        {
            if ( realPos == -1 )
            {
                realPos = ( getExecutable() == null ? 0 : 1 );
                for ( int i = 0; i < position; i++ )
                {
                    Arg arg = (Arg) arguments.elementAt( i );
                    realPos += arg.getParts().length;
                }
            }
            return realPos;
        }


    public void testWrapMemoryMapped() throws Exception {
        File file = File.createTempFile("netty-test", "tmp");
        FileChannel output = null;
        FileChannel input = null;
        ByteBuf b1 = null;
        ByteBuf b2 = null;

        try {
            output = new RandomAccessFile(file, "rw").getChannel();
            byte[] bytes = new byte[1024];
            PlatformDependent.threadLocalRandom().nextBytes(bytes);
            output.write(ByteBuffer.wrap(bytes));

            input = new RandomAccessFile(file, "r").getChannel();
            ByteBuffer m = input.map(FileChannel.MapMode.READ_ONLY, 0, input.size());

            b1 = buffer(m);

            ByteBuffer dup = m.duplicate();
            dup.position(2);
            dup.limit(4);

            b2 = buffer(dup);

            Assert.assertEquals(b2, b1.slice(2, 2));
        } finally {
            if (b1 != null) {
                b1.release();
            }
            if (b2 != null) {
                b2.release();
            }
            if (output != null) {
                output.close();
            }
            if (input != null) {
                input.close();
            }
            file.delete();
        }
    }


    void sharp() {
        final PathAndQuery res = PathAndQuery.parse("/#?a=b#1");
        assertThat(res).isNotNull();
        assertThat(res.path()).isEqualTo("/#");
        assertThat(res.query()).isEqualTo("a=b#1");

        // '%23' in a query string should never be decoded into '#'.
        final PathAndQuery res2 = PathAndQuery.parse("/%23?a=b%231");
        assertThat(res2).isNotNull();
        assertThat(res2.path()).isEqualTo("/#");
        assertThat(res2.query()).isEqualTo("a=b%231");
    }


	public int decryptWithAd(byte[] ad, byte[] ciphertext,
			int ciphertextOffset, byte[] plaintext, int plaintextOffset,
			int length) throws ShortBufferException, BadPaddingException {
		int space;
		if (ciphertextOffset > ciphertext.length)
			space = 0;
		else
			space = ciphertext.length - ciphertextOffset;
		if (length > space)
			throw new ShortBufferException();
		if (plaintextOffset > plaintext.length)
			space = 0;
		else
			space = plaintext.length - plaintextOffset;
		if (keySpec == null) {
			// The key is not set yet - return the ciphertext as-is.
			if (length > space)
				throw new ShortBufferException();
			if (plaintext != ciphertext || plaintextOffset != ciphertextOffset)
				System.arraycopy(ciphertext, ciphertextOffset, plaintext, plaintextOffset, length);
			return length;
		}
		if (length < 16)
			Noise.throwBadTagException();
		int dataLen = length - 16;
		if (dataLen > space)
			throw new ShortBufferException();
		try {
			setup(ad);
		} catch (InvalidKeyException e) {
			// Shouldn't happen.
			throw new IllegalStateException(e);
		} catch (InvalidAlgorithmParameterException e) {
			// Shouldn't happen.
			throw new IllegalStateException(e);
		}
		ghash.update(ciphertext, ciphertextOffset, dataLen);
		ghash.pad(ad != null ? ad.length : 0, dataLen);
		ghash.finish(iv, 0, 16);
		int temp = 0;
		for (int index = 0; index < 16; ++index)
			temp |= (hashKey[index] ^ iv[index] ^ ciphertext[ciphertextOffset + dataLen + index]);
		if ((temp & 0xFF) != 0)
			Noise.throwBadTagException();
		try {
			int result = cipher.update(ciphertext, ciphertextOffset, dataLen, plaintext, plaintextOffset);
			cipher.doFinal(plaintext, plaintextOffset + result);
		} catch (IllegalBlockSizeException e) {
			// Shouldn't happen.
			throw new IllegalStateException(e);
		} catch (BadPaddingException e) {
			// Shouldn't happen.
			throw new IllegalStateException(e);
		}
		return dataLen;
	}


    public List<String> getShellCommandLine( String[] arguments )
    {

        List<String> commandLine = new ArrayList<String>();

        if ( getShellCommand() != null )
        {
            commandLine.add( getShellCommand() );
        }

        if ( getShellArgs() != null )
        {
            commandLine.addAll( getShellArgsList() );
        }

        commandLine.addAll( getCommandLine( getExecutable(), arguments ) );

        return commandLine;

    }


    public void testWhitespaceBeforeTransferEncoding02() {
        String requestStr = "POST / HTTP/1.1" +
                " Transfer-Encoding : chunked\r\n" +
                "Host: target.com" +
                "Content-Length: 65\r\n\r\n" +
                "0\r\n\r\n" +
                "GET /maliciousRequest HTTP/1.1\r\n" +
                "Host: evilServer.com\r\n" +
                "Foo: x";
        testInvalidHeaders0(requestStr);
    }


    public AbstractXmlConfigRootTagRecognizer(String expectedRootNode) throws Exception {
        this.expectedRootNode = expectedRootNode;
        SAXParserFactory factory = SAXParserFactory.newInstance();
        saxParser = factory.newSAXParser();
    }


    public String getEncoding() {
        return encoding;
    }


  public void setUp() throws Exception {
    super.setUp();
    TestUtil.createTempTable(con, "xmltab","x xml");
  }


	private final void servlet31(HttpServletRequest request) {
		try {
			for(Part part:request.getParts()) {
				if(part.getContentType() != null && (StringHelper.containsNonWhitespace(part.getSubmittedFileName()) || !part.getContentType().startsWith("text/plain"))) {
					contentType = part.getContentType();
					filename = part.getSubmittedFileName();
					if(filename != null) {
						filename = UUID.randomUUID().toString().replace("-", "") + "_" + filename;
					} else {
						filename = "upload-" + UUID.randomUUID().toString().replace("-", "");
					}
					file = new File(WebappHelper.getTmpDir(), filename);
					part.write(file.getAbsolutePath());
					file = new File(WebappHelper.getTmpDir(), filename);
				} else {
					String value = IOUtils.toString(part.getInputStream(), request.getCharacterEncoding());
					fields.put(part.getName(), value);
				}

				try {
					part.delete();
				} catch (Exception e) {
					//we try (tomcat doesn't send exception but undertow)
				}
			}
		} catch (IOException | ServletException e) {
			log.error("", e);
		}
	}


	public void testMatchOperation() {

		JWKMatcher matcher = new JWKMatcher.Builder().keyOperation(KeyOperation.DECRYPT).build();

		assertTrue(matcher.matches(new RSAKey.Builder(new Base64URL("n"), new Base64URL("e")).keyID("1")
			.keyOperations(new HashSet<>(Collections.singletonList(KeyOperation.DECRYPT))).build()));
		assertFalse(matcher.matches(new ECKey.Builder(ECKey.Curve.P_256, new Base64URL("x"), new Base64URL("y")).keyID("2").build()));

		assertEquals("key_ops=decrypt", matcher.toString());
	}


  private static String bytesToHex(byte[] bytes, int length) {
    String out = "";
    for (int j = 0; j < length; j++) {
      int v = bytes[j] & 0xFF;
      out += hexArray[v >>> 4];
      out += hexArray[v & 0x0F];
      out += " ";
    }
    return out;
  }


    public JiffleRuntime getRuntimeInstance(Jiffle.RuntimeModel model) throws
            it.geosolutions.jaiext.jiffle.JiffleException {
        return createRuntimeInstance(model, getRuntimeBaseClass(model), false);
    }


    void percent() {
        final PathAndQuery res = PathAndQuery.parse("/%25");
        assertThat(res).isNotNull();
        assertThat(res.path()).isEqualTo("/%25");
        assertThat(res.query()).isNull();
    }


	public void todo_oldTasks() {
		String taskName = UUID.randomUUID().toString();
		PersistentTask ctask = persistentTaskDao.createTask(taskName, new DummyTask());

		//simulate a task from a previous boot
		PersistentTask ptask = new PersistentTask();
		ptask.setCreationDate(new Date());
		ptask.setLastModified(new Date());
		ptask.setName(UUID.randomUUID().toString());
		ptask.setStatus(TaskStatus.inWork);
		ptask.setExecutorBootId(UUID.randomUUID().toString());
		ptask.setExecutorNode(Integer.toString(WebappHelper.getNodeId()));
		ptask.setTask(XStreamHelper.createXStreamInstance().toXML(new DummyTask()));
		dbInstance.getCurrentEntityManager().persist(ptask);

		//simulate a task from an other node
		PersistentTask alienTask = new PersistentTask();
		alienTask.setCreationDate(new Date());
		alienTask.setLastModified(new Date());
		alienTask.setName(UUID.randomUUID().toString());
		alienTask.setStatus(TaskStatus.inWork);
		alienTask.setExecutorBootId(UUID.randomUUID().toString());
		alienTask.setExecutorNode(Integer.toString(WebappHelper.getNodeId() + 1));
		alienTask.setTask(XStreamHelper.createXStreamInstance().toXML(new DummyTask()));
		dbInstance.getCurrentEntityManager().persist(alienTask);

		dbInstance.commitAndCloseSession();

		List<Long> todos = persistentTaskDao.tasksToDo();
		Assert.assertNotNull(todos);
		Assert.assertFalse(todos.isEmpty());
		Assert.assertTrue(todos.contains(ptask.getKey()));
		Assert.assertTrue(todos.contains(ctask.getKey()));
		Assert.assertFalse(todos.contains(alienTask.getKey()));
	}


	public int encryptWithAd(byte[] ad, byte[] plaintext, int plaintextOffset,
			byte[] ciphertext, int ciphertextOffset, int length) throws ShortBufferException {
		int space;
		if (ciphertextOffset > ciphertext.length)
			space = 0;
		else
			space = ciphertext.length - ciphertextOffset;
		if (!haskey) {
			// The key is not set yet - return the plaintext as-is.
			if (length > space)
				throw new ShortBufferException();
			if (plaintext != ciphertext || plaintextOffset != ciphertextOffset)
				System.arraycopy(plaintext, plaintextOffset, ciphertext, ciphertextOffset, length);
			return length;
		}
		if (space < 16 || length > (space - 16))
			throw new ShortBufferException();
		setup(ad);
		encrypt(plaintext, plaintextOffset, ciphertext, ciphertextOffset, length);
		poly.update(ciphertext, ciphertextOffset, length);
		finish(ad, length);
		System.arraycopy(polyKey, 0, ciphertext, ciphertextOffset + length, 16);
		return length + 16;
	}


	public String displayCategoryWithReference(@PathVariable final String friendlyUrl, @PathVariable final String ref, Model model, HttpServletRequest request, HttpServletResponse response, Locale locale) throws Exception {

		return this.displayCategory(friendlyUrl,ref,model,request,response,locale);
	}


	public void testMatchType() {

		JWKMatcher matcher = new JWKMatcher.Builder().keyType(KeyType.RSA).build();

		assertTrue(matcher.matches(new RSAKey.Builder(new Base64URL("n"), new Base64URL("e")).keyID("1").build()));
		assertFalse(matcher.matches(new ECKey.Builder(ECKey.Curve.P_256, new Base64URL("x"), new Base64URL("y")).keyID("2").build()));

		assertEquals("kty=RSA", matcher.toString());
	}


	List<String> cleanForKeySlow(String key) {
		key = StringUtils.trin(StringUtils.goLowerCase(key));
		key = key.replaceAll("_|\\.|\\s", "");
		// key = replaceSmart(key, "partition", "package");
		key = replaceSmart(key, "sequenceparticipant", "participant");
		key = replaceSmart(key, "sequenceactor", "actor");
		key = key.replaceAll("activityarrow", "arrow");
		key = key.replaceAll("objectarrow", "arrow");
		key = key.replaceAll("classarrow", "arrow");
		key = key.replaceAll("componentarrow", "arrow");
		key = key.replaceAll("statearrow", "arrow");
		key = key.replaceAll("usecasearrow", "arrow");
		key = key.replaceAll("sequencearrow", "arrow");
		key = key.replaceAll("align$", "alignment");
		final Matcher2 mm = stereoPattern.matcher(key);
		final List<String> result = new ArrayList<>();
		while (mm.find()) {
			final String s = mm.group(1);
			result.add(key.replaceAll(stereoPatternString, "") + "<<" + s + ">>");
		}
		if (result.size() == 0)
			result.add(key);

		return Collections.unmodifiableList(result);
	}


    private void checkParams()
        throws Exception
    {
        if (vi == null)
        {
            throw new Exception("no layers defined.");
        }
        if (vi.length > 1)
        {
            for (int i = 0; i < vi.length - 1; i++)
            {
                if (vi[i] >= vi[i + 1])
                {
                    throw new Exception(
                        "v[i] has to be smaller than v[i+1]");
                }
            }
        }
        else
        {
            throw new Exception(
                "Rainbow needs at least 1 layer, such that v1 < v2.");
        }
    }


    protected TestPolicy(Policy.ParseContext parseContext) throws PolicyException {
        super(parseContext);
    }


    public static void setRequestMethod(HttpURLConnection conn, RequestMethod method) {
        try {
            conn.setRequestMethod(getRequestMethodAsString(method));
        } catch (ProtocolException e) {
            throw ErrorUtil.createCommandException(e.getMessage());
        }
    }


	public int decryptWithAd(byte[] ad, byte[] ciphertext,
			int ciphertextOffset, byte[] plaintext, int plaintextOffset,
			int length) throws ShortBufferException, BadPaddingException {
		int space;
		if (ciphertextOffset > ciphertext.length)
			space = 0;
		else
			space = ciphertext.length - ciphertextOffset;
		if (length > space)
			throw new ShortBufferException();
		if (plaintextOffset > plaintext.length)
			space = 0;
		else
			space = plaintext.length - plaintextOffset;
		if (!haskey) {
			// The key is not set yet - return the ciphertext as-is.
			if (length > space)
				throw new ShortBufferException();
			if (plaintext != ciphertext || plaintextOffset != ciphertextOffset)
				System.arraycopy(ciphertext, ciphertextOffset, plaintext, plaintextOffset, length);
			return length;
		}
		if (length < 16)
			Noise.throwBadTagException();
		int dataLen = length - 16;
		if (dataLen > space)
			throw new ShortBufferException();
		setup(ad);
		poly.update(ciphertext, ciphertextOffset, dataLen);
		finish(ad, dataLen);
		int temp = 0;
		for (int index = 0; index < 16; ++index)
			temp |= (polyKey[index] ^ ciphertext[ciphertextOffset + dataLen + index]);
		if ((temp & 0xFF) != 0)
			Noise.throwBadTagException();
		encrypt(ciphertext, ciphertextOffset, plaintext, plaintextOffset, dataLen);
		return dataLen;
	}


    public static HttpURLConnection createHttpUrlConnection(URL url, String proxyHost, int proxyPort,
            String proxyUsername, String proxyPassword) {
        try {
            Proxy proxy = getProxy(proxyHost, proxyPort, proxyUsername, proxyPassword);
            // set proxy if exists.
            if (proxy == null) {
                return (HttpURLConnection) url.openConnection();
            } else {
                return (HttpURLConnection) url.openConnection(proxy);
            }
        } catch (IOException e) {
            throw ErrorUtil.createCommandException(e.getMessage());
        }
    }


	public EfficiencyStatement getUserEfficiencyStatementByResourceKey(Long resourceKey, Identity identity){
		StringBuilder sb = new StringBuilder(256);
		sb.append("select statement from effstatementstandalone as statement")
		  .append(" where statement.identity.key=:identityKey and statement.resourceKey=:resourceKey");

		List<UserEfficiencyStatementStandalone> statement = dbInstance.getCurrentEntityManager()
				.createQuery(sb.toString(), UserEfficiencyStatementStandalone.class)
				.setParameter("identityKey", identity.getKey())
				.setParameter("resourceKey", resourceKey)
				.getResultList();
		if(statement.isEmpty() || statement.get(0).getStatementXml() == null) {
			return null;
		}
		return (EfficiencyStatement)xstream.fromXML(statement.get(0).getStatementXml());
	}


    private void verifyHostname(X509Certificate cert)
      throws CertificateParsingException
    {
      try {
        Collection sans = cert.getSubjectAlternativeNames();
        if (sans == null) {
          String dn = cert.getSubjectX500Principal().getName();
          LdapName ln = new LdapName(dn);
          for (Rdn rdn : ln.getRdns()) {
            if (rdn.getType().equalsIgnoreCase("CN")) {
              String peer = client.getServerName().toLowerCase();
              if (peer.equals(((String)rdn.getValue()).toLowerCase()))
                return;
            }
          }
        } else {
          Iterator i = sans.iterator();
          while (i.hasNext()) {
            List nxt = (List)i.next();
            if (((Integer)nxt.get(0)).intValue() == 2) {
              String peer = client.getServerName().toLowerCase();
              if (peer.equals(((String)nxt.get(1)).toLowerCase()))
                return;
            } else if (((Integer)nxt.get(0)).intValue() == 7) {
              String peer = ((CConn)client).getSocket().getPeerAddress();
              if (peer.equals(((String)nxt.get(1)).toLowerCase()))
                return;
            }
          }
        }
        Object[] answer = {"YES", "NO"};
        int ret = JOptionPane.showOptionDialog(null,
          "Hostname verification failed. Do you want to continue?",
          "Hostname Verification Failure",
          JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE,
          null, answer, answer[0]);
        if (ret != JOptionPane.YES_OPTION)
          throw new WarningException("Hostname verification failed.");
      } catch (CertificateParsingException e) {
        throw new SystemException(e.getMessage());
      } catch (InvalidNameException e) {
        throw new SystemException(e.getMessage());
      }
    }


	public VFSContainer createChildContainer(String name) {
		File fNewFile = new File(getBasefile(), name);
		if (!fNewFile.mkdir()) return null;
		LocalFolderImpl locFI =  new LocalFolderImpl(fNewFile, this);
		locFI.setDefaultItemFilter(defaultFilter);
		return locFI;
	}


    public SAXReader(DocumentFactory factory) {
        this.factory = factory;
    }


	private static IRegex getRegexConcat() {
		return RegexConcat.build(CommandBinary.class.getName(), RegexLeaf.start(), //
				new RegexOptional( //
						new RegexConcat( //
								new RegexLeaf("COMPACT", "(compact)"), //
								RegexLeaf.spaceOneOrMore())), //
				new RegexLeaf("binary"), //
				RegexLeaf.spaceOneOrMore(), //
				new RegexLeaf("FULL", "[%g]([^%g]+)[%g]"), //
				RegexLeaf.spaceOneOrMore(), //
				new RegexLeaf("as"), //
				RegexLeaf.spaceOneOrMore(), //
				new RegexLeaf("CODE", "([%pLN_.@]+)"), RegexLeaf.end());
	}


	public int encryptWithAd(byte[] ad, byte[] plaintext, int plaintextOffset,
			byte[] ciphertext, int ciphertextOffset, int length)
			throws ShortBufferException {
		int space;
		if (ciphertextOffset > ciphertext.length)
			space = 0;
		else
			space = ciphertext.length - ciphertextOffset;
		if (!haskey) {
			// The key is not set yet - return the plaintext as-is.
			if (length > space)
				throw new ShortBufferException();
			if (plaintext != ciphertext || plaintextOffset != ciphertextOffset)
				System.arraycopy(plaintext, plaintextOffset, ciphertext, ciphertextOffset, length);
			return length;
		}
		if (space < 16 || length > (space - 16))
			throw new ShortBufferException();
		setup(ad);
		encryptCTR(plaintext, plaintextOffset, ciphertext, ciphertextOffset, length);
		ghash.update(ciphertext, ciphertextOffset, length);
		ghash.pad(ad != null ? ad.length : 0, length);
		ghash.finish(ciphertext, ciphertextOffset + length, 16);
		for (int index = 0; index < 16; ++index)
			ciphertext[ciphertextOffset + length + index] ^= hashKey[index];
		return length + 16;
	}


    public Optional<InputStream> getResourceAsStream(String path) {
        Path filePath = getFilePath(normalize(path));
        try {
            return Optional.of(Files.newInputStream(filePath));
        } catch (IOException e) {
            return Optional.empty();
        }
    }


  private Document parseFromBytes(byte[] bytes) throws SAMLException {
    DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
    documentBuilderFactory.setNamespaceAware(true);
    try {
      DocumentBuilder builder = documentBuilderFactory.newDocumentBuilder();
      return builder.parse(new ByteArrayInputStream(bytes));
    } catch (ParserConfigurationException | SAXException | IOException e) {
      throw new SAMLException("Unable to parse SAML v2.0 authentication response", e);
    }
  }


  public TList readListBegin() throws TException {
    return new TList(readByte(), readI32());
  }


    public BourneShell()
    {
        this( false );
    }


    private ModelAndView renameGroup(HttpServletRequest request, HttpServletResponse response) throws Exception {

        String oldName = request.getParameter("groupName");
        String newName = request.getParameter("newName");

        if (StringUtils.hasText(oldName) && StringUtils.hasText(newName)) {
            m_groupRepository.renameGroup(oldName, newName);
        }

        return listGroups(request, response);
    }


  private byte[] decodeAndInflate(String encodedRequest) throws SAMLException {
    byte[] bytes = Base64.getMimeDecoder().decode(encodedRequest);
    Inflater inflater = new Inflater(true);
    inflater.setInput(bytes);
    inflater.finished();

    try {
      ByteArrayOutputStream baos = new ByteArrayOutputStream();
      byte[] result = new byte[bytes.length];
      while (!inflater.finished()) {
        int length = inflater.inflate(result);
        if (length > 0) {
          baos.write(result, 0, length);
        }
      }

      return baos.toByteArray();
    } catch (DataFormatException e) {
      throw new SAMLException("Invalid AuthnRequest. Inflating the bytes failed.", e);
    }
  }


    private void sendResponse(HttpServletResponse pResp, HttpServletRequest pReq, JSONAware pJson) throws IOException {
        String callback = pReq.getParameter(ConfigKey.CALLBACK.getKeyValue());
        setContentType(pResp, callback != null ? "text/javascript" : getMimeType(pReq));

        pResp.setStatus(HttpServletResponse.SC_OK);
        setNoCacheHeaders(pResp);
        if (pJson == null) {
            pResp.setContentLength(-1);
        } else {
            if (isStreamingEnabled(pReq)) {
                sendStreamingResponse(pResp, callback, (JSONStreamAware) pJson);
            } else {
                // Fallback, send as one object
                // TODO: Remove for 2.0 where should support only streaming
                sendAllJSON(pResp, callback, pJson);
            }
        }
    }


	protected String getCorsDomain(String referer, String userAgent)
	{
		String dom = null;

		if (referer != null && referer.toLowerCase()
				.matches("https?://([a-z0-9,-]+[.])*draw[.]io/.*"))
		{
			dom = referer.toLowerCase().substring(0,
					referer.indexOf(".draw.io/") + 8);
		}
		else if (referer != null && referer.toLowerCase()
				.matches("https?://([a-z0-9,-]+[.])*diagrams[.]net/.*"))
		{
			dom = referer.toLowerCase().substring(0,
					referer.indexOf(".diagrams.net/") + 13);
		}
		else if (referer != null && referer.toLowerCase()
				.matches("https?://([a-z0-9,-]+[.])*quipelements[.]com/.*"))
		{
			dom = referer.toLowerCase().substring(0,
					referer.indexOf(".quipelements.com/") + 17);
		}
		// Enables Confluence/Jira proxy via referer or hardcoded user-agent (for old versions)
		// UA refers to old FF on macOS so low risk and fixes requests from existing servers
		else if ((referer != null
				&& referer.equals("draw.io Proxy Confluence Server"))
				|| (userAgent != null && userAgent.equals(
						"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:50.0) Gecko/20100101 Firefox/50.0")))
		{
			dom = "";
		}

		return dom;
	}


	public PlayerAnalog(String code, ISkinParam skinParam, TimingRuler ruler, boolean compact) {
		super(code, skinParam, ruler, compact);
		this.suggestedHeight = 100;
	}


	public PersistentTask createTask(String name, Serializable task) {
		PersistentTask ptask = new PersistentTask();
		Date currentDate = new Date();
		ptask.setCreationDate(currentDate);
		ptask.setLastModified(currentDate);
		ptask.setName(name);
		ptask.setStatus(TaskStatus.newTask);
		ptask.setTask(xstream.toXML(task));
		dbInstance.getCurrentEntityManager().persist(ptask);
		return ptask;
	}


  public synchronized <T extends Source> T getSource(Class<T> sourceClass) throws SQLException {
    checkFreed();
    ensureInitialized();

    if (data == null) {
      return null;
    }

    try {
      if (sourceClass == null || DOMSource.class.equals(sourceClass)) {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        builder.setErrorHandler(new NonPrintingErrorHandler());
        InputSource input = new InputSource(new StringReader(data));
        return (T) new DOMSource(builder.parse(input));
      } else if (SAXSource.class.equals(sourceClass)) {
        InputSource is = new InputSource(new StringReader(data));
        return (T) new SAXSource(is);
      } else if (StreamSource.class.equals(sourceClass)) {
        return (T) new StreamSource(new StringReader(data));
      } else if (StAXSource.class.equals(sourceClass)) {
        XMLInputFactory xif = XMLInputFactory.newInstance();
        XMLStreamReader xsr = xif.createXMLStreamReader(new StringReader(data));
        return (T) new StAXSource(xsr);
      }
    } catch (Exception e) {
      throw new PSQLException(GT.tr("Unable to decode xml data."), PSQLState.DATA_ERROR, e);
    }

    throw new PSQLException(GT.tr("Unknown XML Source class: {0}", sourceClass),
        PSQLState.INVALID_PARAMETER_TYPE);
  }


	public static void ensurePointOnCurve(final ECPublicKey ephemeralPublicKey, final ECPrivateKey privateKey)
		throws JOSEException {

		// Ensure the following is met:
		// (y^2) mod p = (x^3 + ax + b) mod p
		ECParameterSpec ecParameterSpec = privateKey.getParams();
		EllipticCurve curve = ecParameterSpec.getCurve();
		ECPoint point = ephemeralPublicKey.getW();
		BigInteger x = point.getAffineX();
		BigInteger y = point.getAffineY();
		BigInteger a = curve.getA();
		BigInteger b = curve.getB();
		BigInteger p = ((ECFieldFp) curve.getField()).getP();
		BigInteger leftSide = (y.pow(2)).mod(p);
		BigInteger rightSide = (x.pow(3).add(a.multiply(x)).add(b)).mod(p);

		if (! leftSide.equals(rightSide)) {
			throw new JOSEException("Invalid ephemeral public key: Point not on expected curve");
		}
	}


	protected SymbolContext getContextLegacy() {
		return new SymbolContext(HColorUtils.COL_D7E0F2, HColorUtils.COL_038048).withStroke(new UStroke(1.5));
	}


    protected void configureReader(XMLReader reader, DefaultHandler handler)
            throws DocumentException {
        // configure lexical handling
        SAXHelper.setParserProperty(reader, SAX_LEXICALHANDLER, handler);

        // try alternate property just in case
        SAXHelper.setParserProperty(reader, SAX_LEXICAL_HANDLER, handler);

        // register the DeclHandler
        if (includeInternalDTDDeclarations || includeExternalDTDDeclarations) {
            SAXHelper.setParserProperty(reader, SAX_DECL_HANDLER, handler);
        }

        // string interning
        SAXHelper.setParserFeature(reader, SAX_STRING_INTERNING,
                isStringInternEnabled());

        try {
            // configure validation support
            reader.setFeature("http://xml.org/sax/features/validation",
                    isValidating());

            if (errorHandler != null) {
                reader.setErrorHandler(errorHandler);
            } else {
                reader.setErrorHandler(handler);
            }
        } catch (Exception e) {
            if (isValidating()) {
                throw new DocumentException("Validation not supported for"
                        + " XMLReader: " + reader, e);
            }
        }
    }


  public TMap readMapBegin() throws TException {
    return new TMap(readByte(), readByte(), readI32());
  }


	public static ResourceEvaluation evaluate(File file, String filename) {
		ResourceEvaluation eval = new ResourceEvaluation();
		try {
			ImsManifestFileFilter visitor = new ImsManifestFileFilter();
			Path fPath = PathUtils.visit(file, filename, visitor);
			if(visitor.hasManifest()) {
				Path realManifestPath = visitor.getManifestPath();
				Path manifestPath = fPath.resolve(realManifestPath);

				RootSearcher rootSearcher = new RootSearcher();
				Files.walkFileTree(fPath, rootSearcher);
				if(rootSearcher.foundRoot()) {
					manifestPath = rootSearcher.getRoot().resolve(IMS_MANIFEST);
				} else {
					manifestPath = fPath.resolve(IMS_MANIFEST);
				}

				Document doc = IMSLoader.loadIMSDocument(manifestPath);
				if(validateImsManifest(doc)) {
					if(visitor.hasEditorTreeModel()) {
						XMLScanner scanner = new XMLScanner();
						scanner.scan(visitor.getEditorTreeModelPath());
						eval.setValid(!scanner.hasEditorTreeModelMarkup());
					} else {
						eval.setValid(true);
					}
				} else {
					eval.setValid(false);
				}
			} else {
				eval.setValid(false);
			}
			PathUtils.closeSubsequentFS(fPath);
		} catch (IOException | IllegalArgumentException e) {
			log.error("", e);
			eval.setValid(false);
		}
		return eval;
	}


    public void fatalError(SAXParseException e) {
    }


    public BourneShell( boolean isLoginShell )
    {
        setShellCommand( "/bin/sh" );
        setArgumentQuoteDelimiter( '\'' );
        setExecutableQuoteDelimiter( '\"' );
        setSingleQuotedArgumentEscaped( true );
        setSingleQuotedExecutableEscaped( false );
        setQuotedExecutableEnabled( true );
        setArgumentEscapePattern("'\\%s'");

        if ( isLoginShell )
        {
            addShellArg( "-l" );
        }
    }


    public void testQuoteWorkingDirectoryAndExecutable_WDPathWithSingleQuotes()
    {
        Shell sh = newShell();

        sh.setWorkingDirectory( "/usr/local/'something else'" );
        sh.setExecutable( "chmod" );

        String executable = StringUtils.join( sh.getShellCommandLine( new String[]{} ).iterator(), " " );

        assertEquals( "/bin/sh -c cd \"/usr/local/\'something else\'\" && chmod", executable );
    }


    public void testQuoteWorkingDirectoryAndExecutable()
    {
        Shell sh = newShell();

        sh.setWorkingDirectory( "/usr/local/bin" );
        sh.setExecutable( "chmod" );

        String executable = StringUtils.join( sh.getShellCommandLine( new String[]{} ).iterator(), " " );

        assertEquals( "/bin/sh -c cd /usr/local/bin && chmod", executable );
    }


    private void checkUserReference(UserReference userReference) throws ResetPasswordException
    {
        if (!this.userManager.exists(userReference)) {
            String exceptionMessage =
                this.localizationManager.getTranslationPlain("xe.admin.passwordReset.error.noUser",
                    userReference.toString());
            throw new ResetPasswordException(exceptionMessage);
        }

        // FIXME: This check shouldn't be needed if we'd have the proper API to determine which kind of
        // authentication is used.
        if (!(userReference instanceof DocumentUserReference)) {
            throw new ResetPasswordException("Only user having a page on the wiki can reset their password.");
        }
    }


    public int hashCode()
    {
        return new HashCodeBuilder(17, 37)
            .append(userReference)
            .append(userEmail)
            .append(verificationCode)
            .toHashCode();
    }


    private ModelAndView renameGroup(HttpServletRequest request, HttpServletResponse response) throws Exception {

        String oldName = request.getParameter("groupName");
        String newName = request.getParameter("newName");

        if (StringUtils.hasText(oldName) && StringUtils.hasText(newName)) {
            m_groupRepository.renameGroup(oldName, newName);
        }

        return listGroups(request, response);
    }


	public static byte[] transcodeSignatureToConcat(final byte[] derSignature, int outputLength)
		throws JOSEException {

		if (derSignature.length < 8 || derSignature[0] != 48) {
			throw new JOSEException("Invalid  ECDSA signature format");
		}

		int offset;
		if (derSignature[1] > 0) {
			offset = 2;
		} else if (derSignature[1] == (byte) 0x81) {
			offset = 3;
		} else {
			throw new JOSEException("Invalid  ECDSA signature format");
		}

		byte rLength = derSignature[offset + 1];

		int i;
		for (i = rLength; (i > 0) && (derSignature[(offset + 2 + rLength) - i] == 0); i--) {
			// do nothing
		}

		byte sLength = derSignature[offset + 2 + rLength + 1];

		int j;
		for (j = sLength; (j > 0) && (derSignature[(offset + 2 + rLength + 2 + sLength) - j] == 0); j--) {
			// do nothing
		}

		int rawLen = Math.max(i, j);
		rawLen = Math.max(rawLen, outputLength / 2);

		if ((derSignature[offset - 1] & 0xff) != derSignature.length - offset
			|| (derSignature[offset - 1] & 0xff) != 2 + rLength + 2 + sLength
			|| derSignature[offset] != 2
			|| derSignature[offset + 2 + rLength] != 2) {
			throw new JOSEException("Invalid  ECDSA signature format");
		}

		final byte[] concatSignature = new byte[2 * rawLen];

		System.arraycopy(derSignature, (offset + 2 + rLength) - i, concatSignature, rawLen - i, i);
		System.arraycopy(derSignature, (offset + 2 + rLength + 2 + sLength) - j, concatSignature, 2 * rawLen - j, j);

		return concatSignature;
	}


	public int encryptWithAd(byte[] ad, byte[] plaintext, int plaintextOffset,
			byte[] ciphertext, int ciphertextOffset, int length)
			throws ShortBufferException {
		int space;
		if (ciphertextOffset > ciphertext.length)
			space = 0;
		else
			space = ciphertext.length - ciphertextOffset;
		if (keySpec == null) {
			// The key is not set yet - return the plaintext as-is.
			if (length > space)
				throw new ShortBufferException();
			if (plaintext != ciphertext || plaintextOffset != ciphertextOffset)
				System.arraycopy(plaintext, plaintextOffset, ciphertext, ciphertextOffset, length);
			return length;
		}
		if (space < 16 || length > (space - 16))
			throw new ShortBufferException();
		try {
			setup(ad);
			int result = cipher.update(plaintext, plaintextOffset, length, ciphertext, ciphertextOffset);
			cipher.doFinal(ciphertext, ciphertextOffset + result);
		} catch (InvalidKeyException e) {
			// Shouldn't happen.
			throw new IllegalStateException(e);
		} catch (InvalidAlgorithmParameterException e) {
			// Shouldn't happen.
			throw new IllegalStateException(e);
		} catch (IllegalBlockSizeException e) {
			// Shouldn't happen.
			throw new IllegalStateException(e);
		} catch (BadPaddingException e) {
			// Shouldn't happen.
			throw new IllegalStateException(e);
		}
		ghash.update(ciphertext, ciphertextOffset, length);
		ghash.pad(ad != null ? ad.length : 0, length);
		ghash.finish(ciphertext, ciphertextOffset + length, 16);
		for (int index = 0; index < 16; ++index)
			ciphertext[ciphertextOffset + length + index] ^= hashKey[index];
		return length + 16;
	}


    private JsonNode yamlStreamToJson(InputStream yamlStream) {
        Yaml reader = new Yaml();
        ObjectMapper mapper = new ObjectMapper();
		return mapper.valueToTree(reader.load(yamlStream));
    }


	private static ECPublicKey generateECPublicKey(final ECKey.Curve curve)
		throws Exception {

		final ECParameterSpec ecParameterSpec = curve.toECParameterSpec();

		KeyPairGenerator generator = KeyPairGenerator.getInstance("EC");
		generator.initialize(ecParameterSpec);
		KeyPair keyPair = generator.generateKeyPair();

		return (ECPublicKey) keyPair.getPublic();
	}


    protected Object extractPrincipalFromWebToken(Jwt jwt) {
        Map body = (Map) jwt.getBody();
        String base64Principal = (String) body.get("serialized-principal");
        byte[] serializedPrincipal = Base64.decode(base64Principal);
        Object principal;
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        try {
            Thread.currentThread().setContextClassLoader(codeBase.asClassLoader()); //In case the serialized principal is a POJO entity
            ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(serializedPrincipal)) {
                @Override
                protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
                    return codeBase.loadClass(desc.getName());
                }
            };
            principal = objectInputStream.readObject();
            objectInputStream.close();
        } catch (Exception e) {
            throw new AuthenticationException(e);
        } finally {
            Thread.currentThread().setContextClassLoader(loader);
        }
        return principal;
    }


		public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
	    throws IOException {
	        String filename = file.getFileName().toString();
	        if(filename.endsWith(WikiManager.WIKI_PROPERTIES_SUFFIX)) {
	        		String f = convertAlternativeFilename(file.toString());
	        		final Path destFile = Paths.get(wikiDir.toString(), f);
	        		resetAndCopyProperties(file, destFile);
	        } else if (filename.endsWith(WIKI_FILE_SUFFIX)) {
        			String f = convertAlternativeFilename(file.toString());
	        		final Path destFile = Paths.get(wikiDir.toString(), f);
				Files.copy(file, destFile, StandardCopyOption.REPLACE_EXISTING);
			} else if (!filename.contains(WIKI_FILE_SUFFIX + "-")
					&& !filename.contains(WIKI_PROPERTIES_SUFFIX + "-")) {
				final Path destFile = Paths.get(mediaDir.toString(), file.toString());
				Files.copy(file, destFile, StandardCopyOption.REPLACE_EXISTING);
			}
	        return FileVisitResult.CONTINUE;
		}


	public Player(String title, ISkinParam skinParam, TimingRuler ruler, boolean compact) {
		this.skinParam = skinParam;
		this.compact = compact;
		this.ruler = ruler;
		this.title = Display.getWithNewlines(title);
	}


	public Controller execute(FolderComponent folderComponent, UserRequest ureq, WindowControl wControl, Translator translator) {
		VFSContainer currentContainer = folderComponent.getCurrentContainer();
		VFSContainer rootContainer = folderComponent.getRootContainer();

		if (!VFSManager.exists(currentContainer)) {
			status = FolderCommandStatus.STATUS_FAILED;
			showError(translator.translate("FileDoesNotExist"));
			return null;
		}
		status = FolderCommandHelper.sanityCheck(wControl, folderComponent);
		if (status == FolderCommandStatus.STATUS_FAILED) {
			return null;
		}
		FileSelection selection = new FileSelection(ureq, folderComponent.getCurrentContainerPath());
		status = FolderCommandHelper.sanityCheck3(wControl, folderComponent, selection);
		if (status == FolderCommandStatus.STATUS_FAILED) {
			return null;
		}

		boolean selectionWithContainer = false;
		List<String> filenames = selection.getFiles();
		List<VFSLeaf> leafs = new ArrayList<>();
		for (String file : filenames) {
			VFSItem item = currentContainer.resolve(file);
			if (item instanceof VFSContainer) {
				selectionWithContainer = true;
			} else if (item instanceof VFSLeaf) {
				leafs.add((VFSLeaf) item);
			}
		}
		if (selectionWithContainer) {
			if (leafs.isEmpty()) {
				wControl.setError(getTranslator().translate("send.mail.noFileSelected"));
				return null;
			} else {
				setFormWarning(getTranslator().translate("send.mail.selectionContainsFolder"));
			}
		}
		setFiles(rootContainer, leafs);
		return this;
	}


    public void setEntityResolver(EntityResolver entityResolver) {
        this.entityResolver = entityResolver;
    }


	private TextBlock getTitleBlock(IGroup g) {
		final Display label = g.getDisplay();
		if (label == null)
			return TextBlockUtils.empty(0, 0);

		final ISkinParam skinParam = dotData.getSkinParam();
		final FontConfiguration fontConfiguration;
		if (UseStyle.useBetaStyle()) {
			final SName sname = dotData.getUmlDiagramType().getStyleName();
			final StyleSignatureBasic signature;
			final USymbol uSymbol = g.getUSymbol();
			if (uSymbol == USymbols.RECTANGLE)
				signature = StyleSignatureBasic.of(SName.root, SName.element, sname, uSymbol.getSName(), SName.title);
			else
				signature = StyleSignatureBasic.of(SName.root, SName.element, sname, SName.title);

			final Style style = signature //
					.withTOBECHANGED(g.getStereotype()) //
					.with(g.getStereostyles()) //
					.getMergedStyle(skinParam.getCurrentStyleBuilder());

			fontConfiguration = style.getFontConfiguration(skinParam.getThemeStyle(), skinParam.getIHtmlColorSet());
		} else
			fontConfiguration = g.getFontConfigurationForTitle(skinParam);
		final HorizontalAlignment alignment = HorizontalAlignment.CENTER;
		return label.create(fontConfiguration, alignment, dotData.getSkinParam());
	}


	public <T> T toBean(Class<T> beanClass) {
        setTag(new Tag(beanClass));

		if (getVersion() != null) {
			try {
				MigrationHelper.migrate(getVersion(), beanClass.newInstance(), this);
				removeVersion();
			} catch (InstantiationException | IllegalAccessException e) {
				throw new RuntimeException(e);
			}
		}

        return (T) new OneYaml().construct(this);
	}


	private static String getOrderClause(Set<String> joinAliases, String alias, Order order) {

		String property = order.getProperty();
		boolean qualifyReference = !property.contains("("); // ( indicates a function

		for (String joinAlias : joinAliases) {
			if (property.startsWith(joinAlias.concat("."))) {
				qualifyReference = false;
				break;
			}
		}

		String reference = qualifyReference && StringUtils.hasText(alias) ? String.format("%s.%s", alias, property)
				: property;
		String wrapped = order.isIgnoreCase() ? String.format("lower(%s)", reference) : reference;

		return String.format("%s %s", wrapped, toJpaDirection(order));
	}


	private void parse(UserRequest ureq) {
		String[] sFiles = ureq.getHttpReq().getParameterValues(FORM_ID);
		if (sFiles == null || sFiles.length == 0) return;
		files = Arrays.asList(sFiles);
	}


    public void spliceToFile() throws Throwable {
        EventLoopGroup group = new EpollEventLoopGroup(1);
        File file = File.createTempFile("netty-splice", null);
        file.deleteOnExit();

        SpliceHandler sh = new SpliceHandler(file);
        ServerBootstrap bs = new ServerBootstrap();
        bs.channel(EpollServerSocketChannel.class);
        bs.group(group).childHandler(sh);
        bs.childOption(EpollChannelOption.EPOLL_MODE, EpollMode.LEVEL_TRIGGERED);
        Channel sc = bs.bind(NetUtil.LOCALHOST, 0).syncUninterruptibly().channel();

        Bootstrap cb = new Bootstrap();
        cb.group(group);
        cb.channel(EpollSocketChannel.class);
        cb.handler(new ChannelInboundHandlerAdapter());
        Channel cc = cb.connect(sc.localAddress()).syncUninterruptibly().channel();

        for (int i = 0; i < data.length;) {
            int length = Math.min(random.nextInt(1024 * 64), data.length - i);
            ByteBuf buf = Unpooled.wrappedBuffer(data, i, length);
            cc.writeAndFlush(buf);
            i += length;
        }

        while (sh.future2 == null || !sh.future2.isDone() || !sh.future.isDone()) {
            if (sh.exception.get() != null) {
                break;
            }
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                // Ignore.
            }
        }

        sc.close().sync();
        cc.close().sync();

        if (sh.exception.get() != null && !(sh.exception.get() instanceof IOException)) {
            throw sh.exception.get();
        }

        byte[] written = new byte[data.length];
        FileInputStream in = new FileInputStream(file);

        try {
            Assert.assertEquals(written.length, in.read(written));
            Assert.assertArrayEquals(data, written);
        } finally {
            in.close();
            group.shutdownGracefully();
        }
    }


	public EfficiencyStatement getUserEfficiencyStatementByCourseRepositoryEntry(RepositoryEntry courseRepoEntry, Identity identity){
		UserEfficiencyStatementImpl s = getUserEfficiencyStatementFull(courseRepoEntry, identity);
		if(s == null || s.getStatementXml() == null) {
			return null;
		}
		return (EfficiencyStatement)xstream.fromXML(s.getStatementXml());
	}


    public String getExecutable()
    {
        if ( Os.isFamily( Os.FAMILY_WINDOWS ) )
        {
            return super.getExecutable();
        }

        return unifyQuotes( super.getExecutable());
    }


	public XssHttpServletRequestWrapper(HttpServletRequest request) {
		super(request);
	}


    protected int addFileNames(List<String> list) { // This appears to only be used by unit tests and the copy
                                                    // constructor
        for (String file : list) {
            workUnitList.add(new WorkUnit(file));
        }
        return size();
    }


    private void ondata(String data) {
        try {
            this.decoder.add(data);
        } catch (DecodingException e) {
            this.onerror(e);
        }
    }


	final protected SymbolContext getContext() {
		if (UseStyle.useBetaStyle() == false)
			return getContextLegacy();

		final Style style = getStyleSignature().getMergedStyle(skinParam.getCurrentStyleBuilder());
		final HColor lineColor = style.value(PName.LineColor).asColor(skinParam.getThemeStyle(),
				skinParam.getIHtmlColorSet());
		final HColor backgroundColor = style.value(PName.BackGroundColor).asColor(skinParam.getThemeStyle(),
				skinParam.getIHtmlColorSet());

		return new SymbolContext(backgroundColor, lineColor).withStroke(getStroke());
	}


    void requestResetPasswordUnexistingUser()
    {
        when(this.userReference.toString()).thenReturn("user:Foobar");
        when(this.userManager.exists(this.userReference)).thenReturn(false);
        String exceptionMessage = "User [user:Foobar] doesn't exist";
        when(this.localizationManager.getTranslationPlain("xe.admin.passwordReset.error.noUser",
            "user:Foobar")).thenReturn(exceptionMessage);
        ResetPasswordException resetPasswordException = assertThrows(ResetPasswordException.class,
            () -> this.resetPasswordManager.requestResetPassword(this.userReference));
        assertEquals(exceptionMessage, resetPasswordException.getMessage());
    }


    public Claims validateToken(String token) throws AuthenticationException {
        try {
            RsaKeyUtil rsaKeyUtil = new RsaKeyUtil();
            PublicKey publicKey = rsaKeyUtil.fromPemEncoded(keycloakPublicKey);

            return Jwts.parser().setSigningKey(publicKey).parseJws(token.replace("Bearer ", "")).getBody();
        } catch (Exception e){
            throw new AuthenticationException(String.format("Failed to check user authorization for token: %s", token), e);
        }
    }


	 public void doFilter(ServletRequest srequest, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {

/*	 		HttpServletRequest request = (HttpServletRequest) srequest;
	 		//final String realIp = request.getHeader(X_FORWARDED_FOR);

	 		//if (realIp != null) {
	 			filterChain.doFilter(new XssHttpServletRequestWrapper(request) {
	 				*//**
	 				public String getRemoteAddr() {
	 					return realIp;
	 				}

	 				public String getRemoteHost() {
	 					return realIp;
	 				}
	 				**//*
	 			}, response);

	 			return;
	 		//}

*/

	 }


    private Runnable getDiscoveryRequestSetup(final String url) {
        return new Runnable() {
            public void run() {
                expect(request.getHeader("Origin")).andStubReturn(null);
                expect(request.getHeader("Referer")).andStubReturn(null);
                expect(request.getRemoteHost()).andReturn("localhost");
                expect(request.getRemoteAddr()).andReturn("127.0.0.1");
                expect(request.getRequestURI()).andReturn("/jolokia/");
                expect(request.getParameterMap()).andReturn(null);
                expect(request.getAttribute(ConfigKey.JAAS_SUBJECT_REQUEST_ATTRIBUTE)).andReturn(null);

                expect(request.getPathInfo()).andReturn(HttpTestUtil.HEAP_MEMORY_GET_REQUEST);
                expect(request.getParameter(ConfigKey.MIME_TYPE.getKeyValue())).andReturn("text/plain");
                StringBuffer buf = new StringBuffer();
                buf.append(url).append(HttpTestUtil.HEAP_MEMORY_GET_REQUEST);
                expect(request.getRequestURL()).andReturn(buf);
                expect(request.getRequestURI()).andReturn("/jolokia" + HttpTestUtil.HEAP_MEMORY_GET_REQUEST);
                expect(request.getContextPath()).andReturn("/jolokia");
                expect(request.getAuthType()).andReturn("BASIC");
                expect(request.getAttribute("subject")).andReturn(null);
                expect(request.getParameter(ConfigKey.STREAMING.getKeyValue())).andReturn(null);

            }
        };
    }


    protected SAXContentHandler createContentHandler(XMLReader reader) {
        return new SAXContentHandler(getDocumentFactory(), dispatchHandler);
    }


	final protected CommandExecutionResult executeArg(TimingDiagram diagram, LineLocation location, RegexResult arg) {
		final String compact = arg.get("COMPACT", 0);
		final String code = arg.get("CODE", 0);
		String full = arg.get("FULL", 0);
		if (full == null) {
			full = code;
		}
		final TimingStyle type = TimingStyle.valueOf(arg.get("TYPE", 0).toUpperCase());
		return diagram.createRobustConcise(code, full, type, compact != null);
	}


    public static String printFormattedMetadata(final IBaseDataObject payload) {
        final StringBuilder out = new StringBuilder();
        out.append(LS);
        for (final Map.Entry<String, Collection<Object>> entry : payload.getParameters().entrySet()) {
            out.append(entry.getKey() + SEP + entry.getValue() + LS);
        }
        return out.toString();
    }


	public static void closeSubsequentFS(Path path) {
		if(path != null && FileSystems.getDefault() != path.getFileSystem()) {
			IOUtils.closeQuietly(path.getFileSystem());
		}
	}


    public Document read(Reader reader) throws DocumentException {
        InputSource source = new InputSource(reader);
        if (this.encoding != null) {
            source.setEncoding(this.encoding);
        }

        return read(source);
    }


	final protected Style getStyle() {
		return getStyleSignature().getMergedStyle(skinParam.getCurrentStyleBuilder());

	}


    protected final boolean loadMore() throws IOException
    {
        if (_inputStream != null) {
            _currInputProcessed += _inputEnd;

            int count = _inputStream.read(_inputBuffer, 0, _inputBuffer.length);
            if (count > 0) {
                _inputPtr = 0;
                _inputEnd = count;
                return true;
            }
            // End of input
            _closeInput();
            // Should never return 0, so let's fail
            if (count == 0) {
                throw new IOException("InputStream.read() returned 0 characters when trying to read "+_inputBuffer.length+" bytes");
            }
        }
        return false;
    }


    void sendResetPasswordEmailRequest() throws Exception
    {
        when(this.referenceSerializer.serialize(this.userReference)).thenReturn("user:Foobar");
        when(this.userProperties.getFirstName()).thenReturn("Foo");
        when(this.userProperties.getLastName()).thenReturn("Bar");

        AuthenticationResourceReference resourceReference =
            new AuthenticationResourceReference(AuthenticationAction.RESET_PASSWORD);

        String verificationCode = "foobar4242";
        resourceReference.addParameter("u", "user:Foobar");
        resourceReference.addParameter("v", verificationCode);
        ExtendedURL firstExtendedURL =
            new ExtendedURL(Arrays.asList("authenticate", "reset"), resourceReference.getParameters());
        when(this.resourceReferenceSerializer.serialize(resourceReference)).thenReturn(firstExtendedURL);
        when(this.urlNormalizer.normalize(firstExtendedURL)).thenReturn(
            new ExtendedURL(Arrays.asList("xwiki", "authenticate", "reset"), resourceReference.getParameters())
        );
        XWikiURLFactory urlFactory = mock(XWikiURLFactory.class);
        when(this.context.getURLFactory()).thenReturn(urlFactory);
        when(urlFactory.getServerURL(this.context)).thenReturn(new URL("http://xwiki.org"));

        InternetAddress email = new InternetAddress("foobar@xwiki.org");
        DefaultResetPasswordRequestResponse requestResponse =
            new DefaultResetPasswordRequestResponse(this.userReference, email,
                verificationCode);
        this.resetPasswordManager.sendResetPasswordEmailRequest(requestResponse);
        verify(this.resetPasswordMailSender).sendResetPasswordEmail("Foo Bar", email,
            new URL("http://xwiki.org/xwiki/authenticate/reset?u=user%3AFoobar&v=foobar4242"));
    }


    public void testBourneShellQuotingCharacters()
        throws Exception
    {
        // { ' ', '$', ';', '&', '|', '<', '>', '*', '?', '(', ')' };
        // test with values http://steve-parker.org/sh/bourne.shtml Appendix B - Meta-characters and Reserved Words
        Commandline commandline = new Commandline( newShell() );
        commandline.setExecutable( "chmod" );
        commandline.getShell().setQuotedArgumentsEnabled( true );
        commandline.createArg().setValue( " " );
        commandline.createArg().setValue( "|" );
        commandline.createArg().setValue( "&&" );
        commandline.createArg().setValue( "||" );
        commandline.createArg().setValue( ";" );
        commandline.createArg().setValue( ";;" );
        commandline.createArg().setValue( "&" );
        commandline.createArg().setValue( "()" );
        commandline.createArg().setValue( "<" );
        commandline.createArg().setValue( "<<" );
        commandline.createArg().setValue( ">" );
        commandline.createArg().setValue( ">>" );
        commandline.createArg().setValue( "*" );
        commandline.createArg().setValue( "?" );
        commandline.createArg().setValue( "[" );
        commandline.createArg().setValue( "]" );
        commandline.createArg().setValue( "{" );
        commandline.createArg().setValue( "}" );
        commandline.createArg().setValue( "`" );

        String[] lines = commandline.getShellCommandline();
        System.out.println( Arrays.asList( lines ) );

        assertEquals( "/bin/sh", lines[0] );
        assertEquals( "-c", lines[1] );
        assertEquals( "chmod ' ' '|' '&&' '||' ';' ';;' '&' '()' '<' '<<' '>' '>>' '*' '?' '[' ']' '{' '}' '`'",
                      lines[2] );

    }