text:
<?xml version="1.0" encoding="UTF-8"?>
<!--
  Copyright © 2014 Cask Data, Inc.

  Licensed under the Apache License, Version 2.0 (the "License"); you may not
  use this file except in compliance with the License. You may obtain a copy of
  the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  License for the specific language governing permissions and limitations under
  the License.
  -->

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <parent>
    <artifactId>tephra</artifactId>
    <groupId>co.cask.tephra</groupId>
    <version>0.7.2-SNAPSHOT</version>
  </parent>
  <modelVersion>4.0.0</modelVersion>

  <artifactId>tephra-hbase-compat-1.0-cdh</artifactId>
  <name>Tephra HBase 1.0 Compatibility for CDH</name>

  <properties>
    <!-- CDH 5.4 ships with Hadoop 2.6 -->
    <hadoop.version>2.6.0</hadoop.version>
  </properties>

  <repositories>
    <repository>
      <id>cloudera</id>
      <url>https://repository.cloudera.com/artifactory/cloudera-repos/</url>
    </repository>
  </repositories>

  <dependencies>
    <dependency>
      <groupId>co.cask.tephra</groupId>
      <artifactId>tephra-api</artifactId>
      <version>${project.version}</version>
    </dependency>
    <dependency>
      <groupId>co.cask.tephra</groupId>
      <artifactId>tephra-core</artifactId>
      <version>${project.version}</version>
    </dependency>
    <dependency>
      <groupId>org.apache.hbase</groupId>
      <artifactId>hbase-common</artifactId>
      <version>${hbase10cdh.version}</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>org.apache.hbase</groupId>
      <artifactId>hbase-client</artifactId>
      <version>${hbase10cdh.version}</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>org.apache.hbase</groupId>
      <artifactId>hbase-protocol</artifactId>
      <version>${hbase10cdh.version}</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>org.apache.hbase</groupId>
      <artifactId>hbase-server</artifactId>
      <version>${hbase10cdh.version}</version>
      <scope>provided</scope>
    </dependency>

    <!-- Test dependencies -->
    <dependency>
      <groupId>co.cask.tephra</groupId>
      <artifactId>tephra-core</artifactId>
      <version>${project.version}</version>
      <type>test-jar</type>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
    </dependency>
    <dependency>
      <groupId>org.apache.hbase</groupId>
      <artifactId>hbase-server</artifactId>
      <version>${hbase10cdh.version}</version>
      <type>test-jar</type>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.apache.hbase</groupId>
      <artifactId>hbase-testing-util</artifactId>
      <version>${hbase10cdh.version}</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

</project>


text:
using System.Collections.Generic;
using System.Linq;
using Sanderling.Motor;
using Sanderling.Parse;
using BotEngine.Common;
using Sanderling.ABot.Parse;

namespace Sanderling.ABot.Bot.Task
{
	public class AnomalyEnter : IBotTask
	{
		public const string NoSuitableAnomalyFoundDiagnosticMessage = "no suitable anomaly found. waiting for anomaly to appear.";

		public Bot bot;

        static public bool AnomalySuitableGeneral(Interface.MemoryStruct.IListEntry scanResult) =>
            scanResult?.CellValueFromColumnHeader("Group")?.RegexMatchSuccessIgnoreCase("combat") ?? false;

        public bool AnomalySuitableForBotConfig(Interface.MemoryStruct.IListEntry scanResult)
        {
            var setAnomalyEnabledNamePattern = bot.ConfigSerialAndStruct.Value?.SetAnomalyEnabledNamePattern;
            var anomalyName = scanResult?.CellValueFromColumnHeader("Name");

            return
                setAnomalyEnabledNamePattern?.Any(enabledNamePattern =>
                anomalyName?.RegexMatchSuccessIgnoreCase(enabledNamePattern) ?? false) ?? true;
        }

        public bool AnomalySuitable(Interface.MemoryStruct.IListEntry scanResult) =>
            AnomalySuitableGeneral(scanResult) &&
            AnomalySuitableForBotConfig(scanResult);

        public IEnumerable<IBotTask> Component
        {
            get
            {
                var memoryMeasurementAtTime = bot?.MemoryMeasurementAtTime;
                var memoryMeasurementAccu = bot?.MemoryMeasurementAccu;

                var memoryMeasurement = memoryMeasurementAtTime?.Value;

                if (!memoryMeasurement.ManeuverStartPossible())
                    yield break;

                var probeScannerWindow = memoryMeasurement?.WindowProbeScanner?.FirstOrDefault();

                var scanResultCombatSite =
                    probeScannerWindow?.ScanResultView?.Entry?.FirstOrDefault(AnomalySuitable);

				if (null == scanResultCombatSite)
					yield return new DiagnosticTask
					{
						MessageText = NoSuitableAnomalyFoundDiagnosticMessage,
					};

				if (null != scanResultCombatSite)
					yield return scanResultCombatSite.ClickMenuEntryByRegexPattern(bot, ParseStatic.MenuEntryWarpToAtLeafRegexPattern);
			}
		}

        public MotionParam Motion => null;
    }
}

redpajama_set_name: RedPajamaGithub


text:
CXFA_LayoutProcessor::CXFA_LayoutProcessor(CXFA_Document* pDocument)
    : m_pDocument(pDocument),
      m_nProgressCounter(0),
      m_bNeeLayout(true) {}

CXFA_LayoutProcessor::~CXFA_LayoutProcessor() {}

CXFA_Document* CXFA_LayoutProcessor::GetDocument() const {
  return m_pDocument;
}

int32_t CXFA_LayoutProcessor::StartLayout(bool bForceRestart) {
  if (!bForceRestart && !IsNeedLayout())
    return 100;

  m_pRootItemLayoutProcessor.reset();
  m_nProgressCounter = 0;
  CXFA_Node* pFormPacketNode =
      ToNode(m_pDocument->GetXFAObject(XFA_HASHCODE_Form));
  if (!pFormPacketNode)
    return -1;

  CXFA_Node* pFormRoot =
      pFormPacketNode->GetFirstChildByClass(XFA_Element::Subform);
  if (!pFormRoot)
    return -1;

  if (!m_pLayoutPageMgr)
    m_pLayoutPageMgr = pdfium::MakeUnique<CXFA_LayoutPageMgr>(this);
  if (!m_pLayoutPageMgr->InitLayoutPage(pFormRoot))
    return -1;

  if (!m_pLayoutPageMgr->PrepareFirstPage(pFormRoot))
    return -1;

  m_pRootItemLayoutProcessor = pdfium::MakeUnique<CXFA_ItemLayoutProcessor>(
      pFormRoot, m_pLayoutPageMgr.get());
  m_nProgressCounter = 1;
  return 0;
}

int32_t CXFA_LayoutProcessor::DoLayout(IFX_Pause* pPause) {
  if (m_nProgressCounter < 1)
    return -1;

  XFA_ItemLayoutProcessorResult eStatus;
  CXFA_Node* pFormNode = m_pRootItemLayoutProcessor->GetFormNode();
  FX_FLOAT fPosX = pFormNode->GetMeasure(XFA_ATTRIBUTE_X).ToUnit(XFA_UNIT_Pt);
  FX_FLOAT fPosY = pFormNode->GetMeasure(XFA_ATTRIBUTE_Y).ToUnit(XFA_UNIT_Pt);
  do {
    FX_FLOAT fAvailHeight = m_pLayoutPageMgr->GetAvailHeight();
    eStatus = m_pRootItemLayoutProcessor->DoLayout(true, fAvailHeight,
                                                   fAvailHeight, nullptr);
    if (eStatus != XFA_ItemLayoutProcessorResult::Done)
      m_nProgressCounter++;

    CXFA_ContentLayoutItem* pLayoutItem =
        m_pRootItemLayoutProcessor->ExtractLayoutItem();
    if (pLayoutItem)
      pLayoutItem->m_sPos = CFX_PointF(fPosX, fPosY);

    m_pLayoutPageMgr->SubmitContentItem(pLayoutItem, eStatus);
  } while (eStatus != XFA_ItemLayoutProcessorResult::Done &&
           (!pPause || !pPause->NeedToPauseNow()));

  if (eStatus == XFA_ItemLayoutProcessorResult::Done) {
    m_pLayoutPageMgr->FinishPaginatedPageSets();
    m_pLayoutPageMgr->SyncLayoutData();
    m_bNeeLayout = false;
    m_rgChangedContainers.RemoveAll();
  }
  return 100 * (eStatus == XFA_ItemLayoutProcessorResult::Done
                    ? m_nProgressCounter
                    : m_nProgressCounter - 1) /
         m_nProgressCounter;
}

bool CXFA_LayoutProcessor::IncrementLayout() {
  if (m_bNeeLayout) {
    StartLayout(true);
    return DoLayout(nullptr) == 100;
  }

  for (int32_t i = 0, c = m_rgChangedContainers.GetSize(); i < c; i++) {
    CXFA_Node* pNode = m_rgChangedContainers[i];
    CXFA_Node* pParentNode =
        pNode->GetNodeItem(XFA_NODEITEM_Parent, XFA_ObjectType::ContainerNode);
    if (!pParentNode)
      return false;
    if (!CXFA_ItemLayoutProcessor::IncrementRelayoutNode(this, pNode,
                                                         pParentNode)) {
      return false;
    }
  }
  m_rgChangedContainers.RemoveAll();
  return true;
}

int32_t CXFA_LayoutProcessor::CountPages() const {
  return m_pLayoutPageMgr ? m_pLayoutPageMgr->GetPageCount() : 0;
}

CXFA_ContainerLayoutItem* CXFA_LayoutProcessor::GetPage(int32_t index) const {
  return m_pLayoutPageMgr ? m_pLayoutPageMgr->GetPage(index) : nullptr;
}

CXFA_LayoutItem* CXFA_LayoutProcessor::GetLayoutItem(CXFA_Node* pFormItem) {
  return static_cast<CXFA_LayoutItem*>(
      pFormItem->GetUserData(XFA_LAYOUTITEMKEY));
}

void CXFA_LayoutProcessor::AddChangedContainer(CXFA_Node* pContainer) {
  if (m_rgChangedContainers.Find(pContainer) < 0)
    m_rgChangedContainers.Add(pContainer);
}

CXFA_ContainerLayoutItem* CXFA_LayoutProcessor::GetRootLayoutItem() const {
  return m_pLayoutPageMgr ? m_pLayoutPageMgr->GetRootLayoutItem() : nullptr;
}

bool CXFA_LayoutProcessor::IsNeedLayout() {
  return m_bNeeLayout || m_rgChangedContainers.GetSize() > 0;
}


text:
package com.webfirmframework.wffweb.css;

import java.util.Arrays;
import java.util.List;

import com.webfirmframework.wffweb.InvalidValueException;
import com.webfirmframework.wffweb.NullValueException;
import com.webfirmframework.wffweb.css.core.AbstractCssProperty;
import com.webfirmframework.wffweb.util.StringUtil;
import com.webfirmframework.wffweb.util.TagStringUtil;

/**
 *

 * border-top-width: medium|thin|thick|length|initial|inherit;
 *
 * The border-top-width property sets the width of an element's top border.
 *
 * Note: Always declare the border-style property before the border-top-width property. An element must have borders before you can change the width.
 * Default value:  medium
 * Inherited:      no
 * Animatable:     yes
 * Version:        CSS1
 * JavaScript syntax:      object.style.borderTopWidth="5px"
 *

 *
 *
 * @author WFF
 * @since 1.0.0
 */
public class BorderTopWidth extends AbstractCssProperty<BorderTopWidth> {

    private static final long serialVersionUID = 1_0_0L;

    public static final String MEDIUM = "medium";
    public static final String THIN = "thin";
    public static final String THICK = "thick";
    public static final String INITIAL = "initial";
    public static final String INHERIT = "inherit";

    private static final List<String> PREDEFINED_CONSTANTS = Arrays.asList(INITIAL, INHERIT, MEDIUM, THIN, THICK);

    private String cssValue;
    private Float value;
    private CssLengthUnit cssLengthUnit;

    /**
     * The {@code medium} will be set as the value
     */
    public BorderTopWidth() {
        setCssValue(MEDIUM);
    }

    /**
     * @param cssValue the css value to set.
     */
    public BorderTopWidth(final String cssValue) {
        setCssValue(cssValue);
    }

    /**
     * @param borderTopWidth the {@code BorderTopWidth} object from which the
     *                       cssValue to set.And, {@code null} will throw
     *                       {@code NullValueException}
     */
    public BorderTopWidth(final BorderTopWidth borderTopWidth) {
        if (borderTopWidth == null) {
            throw new NullValueException("borderTopWidth can not be null");
        }
        setCssValue(borderTopWidth.getCssValue());
    }

    /**
     * @param percent the percentage value to set. The cssLengthUnit will
     *                automatically set to %.
     * @since 1.0.0
     * @author WFF
     */
    public BorderTopWidth(final float percent) {
        cssLengthUnit = CssLengthUnit.PER;
        value = percent;
        cssValue = String.valueOf(percent) + cssLengthUnit;
    }

    /**
     * @param value
     * @param cssLengthUnit
     */
    public BorderTopWidth(final float value, final CssLengthUnit cssLengthUnit) {
        this.value = value;
        this.cssLengthUnit = cssLengthUnit;
        cssValue = String.valueOf(value) + cssLengthUnit;
    }

    /**
     * @param value
     * @param cssLengthUnit
     * @return the current object
     * @since 1.0.0
     * @author WFF
     */
    public BorderTopWidth setValue(final float value, final CssLengthUnit cssLengthUnit) {
        this.value = value;
        this.cssLengthUnit = cssLengthUnit;
        cssValue = String.valueOf(value) + cssLengthUnit;
        if (getStateChangeInformer() != null) {
            getStateChangeInformer().stateChanged(this);
        }
        return this;
    }

    /**
     * @param percent the percent to set
     * @since 1.0.0
     * @author WFF
     */
    public void setPercent(final float percent) {
        value = percent;
        cssLengthUnit = CssLengthUnit.PER;
        cssValue = String.valueOf(percent) + cssLengthUnit;
        if (getStateChangeInformer() != null) {
            getStateChangeInformer().stateChanged(this);
        }
    }

    /*
     * (non-Javadoc)
     *
     * @see com.webfirmframework.wffweb.css.CssProperty#getCssName()
     *
     * @since 1.0.0
     *
     * @author WFF
     */
    @Override
    public String getCssName() {
        return CssNameConstants.BORDER_TOP_WIDTH;
    }

    /*
     * (non-Javadoc)
     *
     * @see com.webfirmframework.wffweb.css.CssProperty#getCssValue()
     *
     * @since 1.0.0
     *
     * @author WFF
     */
    @Override
    public String getCssValue() {
        return cssValue;
    }

    @Override
    public String toString() {
        return getCssName() + ": " + getCssValue();
    }

    /**
     * gets the border-top-width in {@code Float} value.
     * {@code BorderTopWidth#getUnit()} should be used to get the cssLengthUnit for
     * this value.
     *
     * @return the value in float or null if the cssValue is initial or
     *         inherit.
     * @since 1.0.0
     * @author WFF
     */
    public Float getValue() {
        return value;
    }

    /**
     * @return the cssLengthUnit {@code PX}/{@code PER}, or {@code null} if the
     *         value is any inbuilt value like {@code inherit}.
     * @since 1.0.0
     * @author WFF
     */
    public CssLengthUnit getUnit() {
        return cssLengthUnit;
    }

    /**
     * @param cssValue the value should be in the format of 55px or
     *                 95%. {@code null} is considered as an invalid
     *                 value and it will throw {@code NullValueException}.
     * @since 1.0.0
     * @author WFF
     */
    @Override
    public BorderTopWidth setCssValue(final String cssValue) {
        final String previousCssValue = this.cssValue;
        try {
            if (cssValue == null) {
                throw new NullValueException(
                        "null is an invalid value. The value format should be as for example 75px or 85%. Or, initial/inherit.");
            } else {
                final String trimmedCssValue = TagStringUtil.toLowerCase(StringUtil.strip(cssValue));
                boolean invalidValue = true;
                for (final CssLengthUnit cssLengthUnit : CssLengthUnit.values()) {
                    final String unit = cssLengthUnit.getUnit();
                    if (trimmedCssValue.endsWith(unit)) {
                        final String valueOnly = trimmedCssValue.replaceFirst(unit, "");
                        try {
                            value = Float.parseFloat(valueOnly);
                        } catch (final NumberFormatException e) {
                            break;
                        }
                        this.cssLengthUnit = cssLengthUnit;
                        this.cssValue = cssValue;
                        invalidValue = false;
                        break;
                    }
                }
                if (PREDEFINED_CONSTANTS.contains(trimmedCssValue)) {
                    this.cssValue = trimmedCssValue;
                    cssLengthUnit = null;
                    value = null;
                    invalidValue = false;
                }
                if (invalidValue) {
                    throw new InvalidValueException(cssValue
                            + " is an invalid value. The value format should be as for example 75px, 85%, initial, inherit etc..");
                }
            }
            if (getStateChangeInformer() != null) {
                getStateChangeInformer().stateChanged(this);
            }
        } catch (final NumberFormatException | InvalidValueException e) {
            this.cssValue = previousCssValue;
            throw new InvalidValueException(cssValue
                    + " is an invalid value. The value format should be as for example 75px or 85%. Or, initial/inherit.",
                    e);
        }
        return this;
    }

    /**
     * sets as {@code initial}
     *
     * @since 1.0.0
     * @author WFF
     */
    public void setAsInitial() {
        setCssValue(INITIAL);
    }

    /**
     * sets as {@code inherit}
     *
     * @since 1.0.0
     * @author WFF
     */
    public void setAsInherit() {
        setCssValue(INHERIT);
    }

    /**
     * sets as {@code medium}.
     *
     * @since 1.0.0
     * @author WFF
     */
    public void setAsMedium() {
        setCssValue(MEDIUM);
    }

    /**
     * sets as {@code thin}.
     *
     * @since 1.0.0
     * @author WFF
     */
    public void setAsThin() {
        setCssValue(THIN);
    }

    /**
     * sets as {@code thick}.
     *
     * @since 1.0.0
     * @author WFF
     */
    public void setAsThick() {
        setCssValue(THICK);
    }

    /**
     * validates if the given cssValue is valid for this class.
     *
     * @param cssValue the value to check.
     * @return true if valid and false if invalid.
     * @author WFF
     * @since 1.0.0
     */
    public static boolean isValid(final String cssValue) {

        final String trimmedCssValue = StringUtil.strip(cssValue).toLowerCase();

        if (StringUtil.containsSpace(trimmedCssValue)) {
            return false;
        }

        for (final CssLengthUnit cssLengthUnit : CssLengthUnit.values()) {
            final String unit = cssLengthUnit.getUnit();
            if (trimmedCssValue.endsWith(unit)) {
                final String valueOnly = trimmedCssValue.replaceFirst(unit, "");
                try {
                    Float.parseFloat(valueOnly);
                } catch (final NumberFormatException e) {
                    break;
                }
                return true;
            }
        }

        return PREDEFINED_CONSTANTS.contains(trimmedCssValue);
    }

}


text:
requirejs.config({
  paths: {
  	'baidumaps': '/js/baidumaps',
    'tencentmaps': '/js/tencentmaps',
	'googlemaps': '/js/googlemaps',
	'BmapLib':'/js/EventWrapper',
	'config': '/js/config',
	'jquery': '/js/lib/jquery/jquery-2.0.3.min',
    'jquery-private': '/js/jquery-private'
  },
  shim: {
    'config': { exports: 'config' },
    'tencentmaps': {
     deps: [
		'async!http://map.qq.com/api/js?v=2.exp&libraries=geometry&key=S5PBZ-MX53W-2AHRY-R7Y5S-WTCW6-OLFRF&sensor=false!callback'
		]
    },
	'baidumaps': {
      deps: [
       'async!http://api.map.baidu.com/api?v=2.0&libraries=geometry&ak=NkArbcs6kW74wrlpZcTNHU2g&sensor=false!callback'
      ]
	},

	'googlemaps': {
      deps: [
        'async!http://maps.googleapis.com/maps/api/js?v=3.exp&libraries=geometry&sensor=false!callback'
      ]
    }
  },
  map: {
    '*': { 'jquery': 'jquery-private' },
    'jquery-private': { 'jquery': 'jquery' }
  }
});

define(['baidumaps','tencentmaps','googlemaps','BmapLib','config','jquery'], function(BMaps,QMaps,GMaps,BmapLib,config,$) {
   var apiProvider = config.provider;
   var tencentKey = config.tencentKey;
   var baiduKey = config.baiduKey;
   var StreetViewStatus = {
	OK: GMaps.StreetViewStatus.OK,
   };

   function SetProvider(app) {
	var providerID;
	if(app == 'google')
		providerID = 1;
	else if(app == 'tencent')
		providerID = 2;
	else if(app == 'baidu')
		providerID = 3;
	else providerID = 1;

    apiProvider = providerID;
   }

   //base class
   function LatLng(lat,lng)
   {
     var loc;
	 if(apiProvider==1)
	    loc = new GMaps.LatLng(lat,lng);
	 else if(apiProvider==2)
		loc = new QMaps.LatLng(lat,lng);
	 else if(apiProvider==3)
		loc = new BMaps.Point(lng,lat);
	 return loc;
   }

   function Point(x,y)
   {
     var point;
	 if(apiProvider==1)
		point = new GMaps.Point(x,y);
	 else if(apiProvider==2)
		point = new QMaps.Point(x,y);
	 else if(apiProvider==3)
		point = new BMaps.Pixel(x,y);
	 return point;
   }

   function Size(width,height)
   {
     var size;

	 if(apiProvider==1)
		size = new GMaps.Size(width,height);
	 else if(apiProvider==2)
		size = new QMaps.Size(width,height);
	 else if(apiProvider==3)
		size = new BMaps.Size(width,height);
	 return size;
   }

    // street view service
	function StreetViewService() {

	  var sv;
	  switch(apiProvider)
	  {
	  case 1:
		sv = new GMaps.StreetViewService();
	    break;
	  case 2:
		sv = QMaps.PanoramaService();
	    break;
	  case 3:
		sv = BMaps.PanoramaService();
		break;
	  }
	  return sv;
   }

   function getPanoramaById(panoid,cb)
   {
	  switch(apiProvider)
	  {
	  case 1:
	    var sv_svc = new GMaps.StreetViewService();
		sv_svc.getPanoramaById(panoid,cb);
	    break;

	  case 2:
	    var data = null;
		console.log(panoid);
	    if (panoid.match(/^\w+$/))
	    {
		$.getJSON("http://apis.map.qq.com/ws/streetview/v1/getpano?id="+panoid+"&radius=100&key="+tencentKey+"&output=jsonp&callback=?",
	      function(ret) {
		  console.log(ret.status);
		  if(ret.status == 0)
		  {
			data = {
				location: {pano:ret.detail.id,latLng: new QMaps.LatLng(ret.detail.location.lat,ret.detail.location.lng),description:ret.detail.description}
			};
		    cb(data,StreetViewStatus.OK);
		  }
	     });
	    }
	    break;

	  case 3:
		data = null;
		console.log("apiProvider 3");
	    var sv_svc = new BMaps.PanoramaService();
		sv_svc.getPanoramaById(panoid,
			function(ret){
			if (ret == null) {
				return;
			}
			data = {
			location: {pano:ret.id,latLng:ret.position,description:ret.description},
			links:ret.links,
			tiles:ret.tiles
			};
			cb(data,StreetViewStatus.OK);
		});
		break;
	  }
   }

   function getPanoramaByLocation(position, radius, cb)
   {
	  switch(apiProvider)
	  {
	  case 1:
	    var sv_svc = new GMaps.StreetViewService();
		sv_svc.getPanoramaByLocation(position,radius,cb);
	    break;

	  case 2:
	    var sv_svc = new QMaps.PanoramaService();
		sv_svc.getPano(position,radius,function(ret) {
		  if(ret !== 0){
			data = {
				location: {pano:ret.id,latLng:ret.latlng,description:ret.description}
			};
		    cb(data,StreetViewStatus.OK);
		  }
	     });
		break;

	  case 3:
	    var sv_svc = new BMaps.PanoramaService();
		sv_svc.getPanoramaByLocation(position,radius,function(ret){
			if (ret == null) {
				return;
			}
			data = {
			location: {pano:ret.id,latLng:ret.position,description:ret.description},
			links:ret.links,
			tiles:ret.tiles
			};
			cb(data,StreetViewStatus.OK);
		});
		break;
	  }
   }

   //Map Module
   function Map(div,opt)
   {
      var map;
	  switch(apiProvider)
	{
	 case 1:
		map = new GMaps.Map(div,opt);
		map.addOverlay = function(overlay){};
		break;
	 case 2:
		map = new QMaps.Map(div,opt);
		map.addOverlay = function(overlay){};
		map.setStreetView = function(streetview){};
		break;
	 case 3:
		bmapOpt = {	mapType: opt.mapTypeID};
		bmapTypeOpt = {
			mapTypes: opt.mapTypeControlOptions.mapTypeIds,
			anchor: opt.mapTypeControlOptions.position
		};
		map = new BMaps.Map(div,bmapOpt);
		map.setZoom(opt.zoom);
		map.setCenter(opt.center);
		if(opt.mapTypeControl)
			map.addControl(new BMap.MapTypeControl(bmapTypeOpt));

		//member
		map.setStreetView = function(streetview){
			map.setPanorama(streetview);
		};
		break;
	 }
	  map.visualRefresh = true;
	  return map;
   }

   function MapTypeId()
   {
    var typeid;
     switch(apiProvider)
	 {
     case 1:
		return GMaps.MapTypeId;
		break;
	 case 2:
	   return QMaps.MapTypeId;
	   break;
	 case 3:
		var type = new BMaps.MapType;
		var typeid = {
			ROADMAP : type.BMAP_NORMAL_MAP,
			HYBRID : type.BMAP_PERSPECTIVE_MAP,
		};
	  break;
	 }
	 return typeid;
   }

   function ControlPosition()
   {
     switch(apiProvider)
	 {
     case 1:
      return GMaps.ControlPosition;
	  break;
	 case 2:
	  return QMaps.ControlPosition;
	   break;
	 case 3:
	  var contr_pos = {
		TOP_LEFT: BMaps.ControlAnchor.MAP_ANCHOR_TOP_LEFT,
		TOP_RIGHT: BMaps.ControlAnchor.BMAP_ANCHOR_TOP_RIGHT,
		BOTTOM_LEFT: BMaps.ControlAnchor.BMAP_ANCHOR_BOTTOM_LEFT,
		BOTTOM_RIGHT: BMaps.ControlAnchor.BMAP_ANCHOR_BOTTOM_RIGHT
	  }
	  break;
	}
	  return ;
   }

    //Coverage Module
   function StreetViewCoverageLayer()
   {
     var sv_coverage_layer;

     switch(apiProvider)
	 {
	 case 1:
		sv_coverage_layer = new GMaps.StreetViewCoverageLayer();
		break;
	 case 2:
	    sv_coverage_layer = new QMaps.PanoramaLayer();
		break;
	 case 3:
	    sv_coverage_layer = new BMaps.PanoramaCoverageLayer();
		sv_coverage_layer.setMap = function(map){
			if(map == null)	map.removeTileLayer();
			else map.addTileLayer(sv_coverage_layer);
		};
		break;
	}
	 return sv_coverage_layer;
   }

   //Marker Module
	function Marker(opt)
   {
      var marker;
      switch(apiProvider)
	  {
	  case 1:
		marker = new GMaps.Marker(opt);
	    break;
	  case 2:
        marker = new QMaps.Marker(opt);
		break;
	  case 3:
		point = opt.position;
		mkrOption = {
			title: opt.title,
			icon: opt.icon,
			enableClicking: opt.clickable
		}
        marker = new BMaps.Marker(point,mkrOption);
		marker.setMap = function(map){
			if(null !== map) map.addOverlay(marker);
			else map.removeOverlay();
		}
		if(opt.map !== null) marker.setMap(opt.map);
		break;
	  }
	  return marker;
   }

   //infoWindow
   function InfoWindow(opt)
   {
      var info;
	  if(apiProvider==1){
		info = new GMaps.InfoWindow({
        content: opt.content,
        disableAutoPan: opt.disableAutoPan
      });
		info.openInfoWindow = function(map,latlng){
			info.setPosition(latlng);
			info.open(map);
		}
		info.closeInfoWindow = function(map){
			info.close();
		};
	  }
	  else if(apiProvider==2){
		info = new QMaps.InfoWindow({
        content: opt.content,
		map: opt.map
      });
		info.openInfoWindow = function(map,latlng){
			info.setPosition(latlng);
			info.open();
		}
		info.closeInfoWindow = function(map){
			info.close();
		};
	  }
	  else if(apiProvider==3){
		var enableAutoPan = true;
		if(opt.disableAutoPan == true)
			enableAutoPan = false;
		info = new BMaps.InfoWindow(opt.content,{
		enableAutoPan: enableAutoPan
      });
		info.openAtPosition = function(map,latlng){
			map.openInfoWindow(info, latlng);
		}
		info.closeInfoWindow = function(map){
			map.closeInfoWindow();
		};
	  }
	  return info;
   }

   //StreetViewPanorama
   function StreetViewPanorama(div,opt)
   {
     var streetview;
	 switch(apiProvider)
	  {
	  case 1:
		streetview = new GMaps.StreetViewPanorama(div,opt);
		break;
      case 2:
	    streetview = new QMaps.Panorama(div,opt);
		break;
	  case 3:
		bmapPanoOpt = {
		  navigationControl: opt.scrollwheel,
		};
	    streetview = new BMaps.Panorama(div,bmapPanoOpt);
		break;
	  }
     return streetview;
   }

   //Listener
   function addListener(instance, eventName, handler)
   {
	  switch(apiProvider)
	  {
	  case 1:
	     GMaps.event.addListener(instance, eventName,handler);
		 break;
	  case 2:
		 QMaps.event.addListener(instance, eventName,handler);
		 break;
	  case 3:
		 var evtname = eventName;
		 if(eventName == 'idle') evtname = 'tilesloaded';
		 else if(eventName == 'zoom_changed') evtname = 'zoomend';
		 else if(eventName == 'zoom_changed') evtname = 'zoomend';
		 else if(eventName == 'pano_changed') evtname = 'position_changed';
		 BMapLib.EventWrapper.addListener(instance, evtname, handler);
		 break;
	  }
   }

   function addListenerOnce(instance, eventName, handler)
   {
      if(apiProvider==1)
		GMaps.event.addListenerOnce(instance, eventName,handler);
	  else if(apiProvider==2)
		QMaps.event.addListenerOnce(instance, eventName,handler);
	  else if(apiProvider==3)
		BMapLib.EventWrapper.addListenerOnce(instance, eventName, handler);
   }

   function trigger(instance, eventName)
   {
     if(apiProvider==1)
       GMaps.event.trigger(instance, eventName);
	 else if(apiProvider==2)
	   QMaps.event.trigger(instance, eventName);
	 else if(apiProvider==3)
	   BMapLib.EventWrapper.trigger(instance, eventName);
   }

  //////////////////////////////////////////////////////////////
  /////////////////////////////////////////////////////////////
  ////////////////////////////////////////////////////////////////
  ////////////////////////////////////////////////////////////////
   function computeOffset(from, distance, heading)
   {
     var loc = null;
     if(apiProvider==1)
	    loc = GMaps.geometry.spherical.computeOffset(from, distance, heading);
	 else if(apiProvider==2)
	    loc = QMaps.geometry.spherical.computeOffset(from, distance, heading);
	 else if(apiProvider==3) ;
	 //   loc = BMaps.geometry.spherical.computeOffset(from, distance, heading);  //?
	 return loc;
   }

   function disableDefaultUI(map,mystyle)
   {
    if(apiProvider==1)
	{
	if(mystyle!="")
      map.setOptions({styles: mystyle,disableDefaultUI: true});
	 else
	  map.setOptions({disableDefaultUI: true});
	}
	else if(apiProvider==2)
	{
	  map.setOptions({navigationControl: false,
		scaleControl: false,
		panControl: false,
		zoomControl: false,
		mapTypeControl:false});
	 }
	else if(apiProvider==3)
	{

	}
   }

   function disableSVDefaultUI()
   {

    var svOptions;
    if(apiProvider==1)
	{
	  svOptions = {
        visible: true,
        disableDefaultUI: true
      };
	}
	else if(apiProvider==2)
	{
	  svOptions = {
	    visible: true,
        disableCompass: true,
		disableMove:false
	  };
	}
	else if(apiProvider==3)
	{
	  svOptions = {
	    navigationControl: false,
		indoorSceneSwitchControl:false
	  };
	}
	 return svOptions;
   }

   function enableSVDefaultUI(svOptions)
   {
     if(apiProvider==1)
	 {
	    svOptions.linksControl = true;
	 }
     else if(apiProvider==2)
	 {
	    svOptions.linksControl = true;
		svOptions.disableCompass = false;
		svOptions.disableMove = false;
	 }
 	 else if(apiProvider==3)
	 {
	    svOptions.navigationControl=true;
		svOptions.indoorSceneSwitchControl=true;
	 }
   }

   function setHdgIcon(headingIndex)
   {
     var markerIcon;
     if(apiProvider==1)
	 {
	    var sWidth = 56.75*parseInt(headingIndex%4);
	    var sHeight = 56.75*parseInt(headingIndex/4);
		markerIcon = {
	      url: 'icons/sv_markers.png',
          // This marker is 56.75 pixels wide by 56.75 pixels tall.
          size: new GMaps.Size(56.75,56.75),
          // The origin for this image is sWidth,sHeight.
          origin: new GMaps.Point(sWidth,sHeight),
          // The anchor for this image is the base of the flagpole at 56.75/2,40.
          anchor: new GMaps.Point(56.75/2,40)
	   };
	 }
	 else if(apiProvider==2)
	 {
	    var sWidth = 56.67*parseInt(headingIndex%3);
		var sHeight = 56.75*parseInt(headingIndex/3);
		markerIcon = new QMaps.MarkerImage(
		"icons/sv_soso_markers.png",
		new QMaps.Size(56.67,56.75),
		new QMaps.Point(sWidth,sHeight),
		new QMaps.Point(56.67/2,32)
		);
	 }
	 else if(apiProvider==3)
	 {
	    var sWidth = 56.67*parseInt(headingIndex%3);
		var sHeight = 56.75*parseInt(headingIndex/3);
		markerIcon = {
		imageUrl: "icons/sv_soso_markers.png",
		imageSize: new BMaps.Size(56.67,56.75),
		imageOffset: new BMaps.Pixel(sWidth,sHeight),
		anchor: new BMaps.pixel(56.67/2,32)
		}

	 }
	 return markerIcon;
   }

   function otherSet(streetview,map,zoom,mymode)
   {
     if(apiProvider==1)
	 {
	    streetview.setOptions({ mode: mymode });
       // *** apply the custom streetview object to the map
        map.setStreetView( streetview );
	 }
	 else if(apiProvider==2)
	 {
	   streetview.setZoom(zoom);
	 }
	 else if(apiProvider==3)
	 {
	   streetview.setZoom(zoom);
	 }
   }

   function MarkerIndex(heading)
   {
     var nindex;
     if(apiProvider==1)
	   nindex = parseInt(heading/22.5)%16;
	 else if(apiProvider==2)
	   nindex = parseInt(heading/30)%12;
	 else if(apiProvider==3)
	   nindex = parseInt(heading/30)%12;
	  return nindex;
   }

   function DefaultCenter(centerarr)
   {
     var center = new Array();;
     if(apiProvider==1)
	 {
	   center[0] = centerarr[0].lat;
	   center[1] = centerarr[0].lng;
	 }
	 else if(apiProvider==2)
	 {
	   center[0] = centerarr[1].lat;
	   center[1] = centerarr[1].lng;
	  }
	 else if(apiProvider==3)
	 {
	   center[0] = centerarr[2].lng;
	   center[1] = centerarr[2].lat;
	  }
	  return center;
   }

   function DeletePoi(poiArr)
   {
      var nPoiArr = poiArr;

	  for(var i = 0; i < poiArr.length; ++i)
	  {
	    var nPoiSubArr = new Array();
	   for(var j = 0; j < poiArr[i].objects.length; ++j)
	   {
	     if((poiArr[i].objects[j].identifier).match(/^[\w-]{22}$/)&&apiProvider==1)
		 {
		    nPoiSubArr.push(poiArr[i].objects[j]);
		 }
		 else if(!(poiArr[i].objects[j].identifier).match(/^[\w-]{22}$/)&&apiProvider==2)
		 {
		    nPoiSubArr.push(poiArr[i].objects[j]);
		 }
	   }
	    nPoiArr[i].objects = nPoiSubArr;
	  }
	  return nPoiArr;
   }

  return{
	apiProvider: apiProvider,
	StreetViewStatus: StreetViewStatus,
	StreetViewService: StreetViewService,
	computeOffset: computeOffset,
	LatLng: LatLng,
	Size: Size,
	Point: Point,
	Map: Map,
	StreetViewPanorama: StreetViewPanorama,

	Marker: Marker,

	MapTypeId: MapTypeId,
	ControlPosition: ControlPosition,
	InfoWindow: InfoWindow,
	trigger: trigger,
	getPanoramaByLocation: getPanoramaByLocation,
	getPanoramaById: getPanoramaById,
	disableDefaultUI: disableDefaultUI,
	disableSVDefaultUI: disableSVDefaultUI,
	enableSVDefaultUI: enableSVDefaultUI,
	StreetViewCoverageLayer:StreetViewCoverageLayer,

	addListener: addListener,
	addListenerOnce: addListenerOnce,

	setHdgIcon:setHdgIcon,
	otherSet:otherSet,

	MarkerIndex:MarkerIndex,
	DefaultCenter:DefaultCenter,
	SetProvider:SetProvider,
	DeletePoi:DeletePoi,
  }
});


text:
<?php
// test variables definition
define('TEST_CLASS', 'Logger');
define('TEST_CLASS_2', 'Alert');
define('TEST_NON_TAGGABLE_CLASS', 'Event');

// initializes testing framework
$sf_root_dir = realpath(dirname(__FILE__).'/../../../../');
$apps_dir = glob($sf_root_dir.'/apps/*', GLOB_ONLYDIR);
$app = substr($apps_dir[0],
              strrpos($apps_dir[0], DIRECTORY_SEPARATOR) + 1,
              strlen($apps_dir[0]));
if (!$app)
{
  throw new Exception('No app has been detected in this project');
}

// initialize database manager
require_once($sf_root_dir.'/test/bootstrap/unit.php');

if (SYMFONY_VERSION >= 1.1)
{
  $configuration = ProjectConfiguration::getApplicationConfiguration($app, 'test', true);
  $databaseManager = new sfDatabaseManager($configuration);
}
else
{
  // initialize database manager
  require_once($sf_root_dir.'/test/bootstrap/functional.php');
  require_once($sf_symfony_lib_dir.'/vendor/lime/lime.php');

  $databaseManager = new sfDatabaseManager();
  $databaseManager->initialize();
  $con = Propel::getConnection();
}

if (!defined('TEST_CLASS') || !class_exists(TEST_CLASS)
    || !defined('TEST_CLASS_2') || !class_exists(TEST_CLASS_2))
{
  // Don't run tests
  return;
}

// clean the database
Doctrine_Query::create()->delete()->from('Tag')->execute();
Doctrine_Query::create()->delete()->from('Tagging')->execute();
Doctrine_Query::create()->delete()->from(TEST_CLASS)->execute();
Doctrine_Query::create()->delete()->from(TEST_CLASS_2)->execute();

// create a new test browser
// $browser = new sfTestBrowser();
// $browser->initialize();

// start tests
$t = new lime_test(66, new lime_output_color());

// these tests check for the tags attachement consistency
$t->diag('tagging consistency');

$object = _create_object();
$t->ok($object->getTags() == array(), 'a new object has no tag.');

$object->addTag('toto');
$object_tags = $object->getTags();
$t->ok((count($object_tags) == 1) && ($object_tags['toto'] == 'toto'), 'a non-saved object can get tagged.');

$object->addTag('toto');
$object_tags = $object->getTags();
$t->ok(count($object_tags) == 1, 'a tag is only applied once to non-saved objects.');
$object->save();

$object->addTag('toto');
$object_tags = $object->getTags();
$t->ok(count($object_tags) == 1, 'a tag is also only applied once to saved objects.');
$object->save();

$object->addTag('tutu');
$object_tags = $object->getTags();
$t->ok($object->hasTag('tutu'), 'a saved object can get tagged.');
$object->save();

// get the key of this object
$id1 = $object->getPrimaryKey();

$object->removeTag('tutu');
$t->ok(!$object->hasTag('tutu'), 'a previously saved tag can be removed.');

$object->addTag('tata');
$object->removeTag('tata');
$t->ok(!$object->hasTag('tata'), 'a non-saved tag can also be removed.');

$object->addTag('tu\'tu');
$t->ok($object->hasTag('tu\'tu'), 'a tag can contain a quote.');

$object2 = _create_object();
$object_tags = $object2->getTags();
$t->ok(count($object_tags) == 0, 'a new object has no tag, even if other tagged objects exist.');
$object2->save();

$object2->addTag('titi');
$t->ok($object2->hasTag('titi'), 'a new object can get tagged, even if other tagged objects exist.');
$t->ok(!$object->hasTag('titi'), 'tags applied to new objects do not affect old ones.');
$object2->save();
$id2 = $object2->getPrimaryKey();

$object = _create_object();
$object->addTag('tutu');
$object->addTag('titi');
$object->save();
$object->addTag('tata');
$object->removeAllTags();
$t->ok(!$object->hasTag(), 'tags can all be removed at once.');

$object = _create_object();
$object->addTag('toto,international,tata');
$object->save();
$id = $object->getPrimaryKey();
$object = Doctrine::getTable(TEST_CLASS)->findOneById($id);
$object->removeTag('tata');
$object->addTag('tata');
$object->save();
$object = Doctrine::getTable(TEST_CLASS)->findOneById($id);
$object_tags = $object->getTags();
$t->ok(count($object_tags) == 3, 'when removing one previously saved tag, then restoring it, and then saving it again, this tag is not duplicated.');

$object = _create_object();
$object->addTag('toto,tutu,tata');
$object->save();
$object->removeAllTags();
$object->addTag('toto,tutu,tata');
$object->save();
$id = $object->getPrimaryKey();
$object = Doctrine::getTable(TEST_CLASS)->findOneById($id);
$object_tags = $object->getTags();
$t->ok(count($object_tags) == 3, 'when removing all previously saved tags, then restoring it, and then saving it again, tags are not duplicated.');

$object = _create_object();
$object->addTag('toto,tutu,tata');
$object->save();
$previous_count = count($object->getTags());
$object->removeAllTags();
$object->save();
$id = $object->getPrimaryKey();
$object = Doctrine::getTable(TEST_CLASS)->findOneById($id);
$t->ok(($previous_count == 3) && !$object->hasTag(), 'previously in-database tags can be deleted.');

$object = _create_object();
$object->addTag('toto, tutu, test');
$object->save();
$id = $object->getPrimaryKey();
$object = Doctrine::getTable(TEST_CLASS)->findOneById($id);

$object2 = _create_object();
$object2->addTag('clever age, symfony, test');
$object2->save();
$object2->removeTag('test');
$object2->save();

$object_tags = $object->getTags();
$object2_tags = $object2->getTags();
$t->ok((count($object2_tags) == 2) && (count($object_tags) == 3), 'removing one tag as no effect on the other tags of the object, neither on the other objects.');

$object2_tags = $object2->getTags(array('serialized' => true));
$t->ok($object2_tags == 'clever age, symfony', 'tags can be retrieved in a serialized form.');

$object->removeAllTags();
$object->setTags('');
$object->save();
$id = $object->getPrimaryKey();
$object = Doctrine::getTable(TEST_CLASS)->findOneById($id);
$t->ok(count($object->getTags()) == 0, 'when the tags are set twice, or all removed twice, before the object is saved, then all the prvious tags are still removed.');

unset($object, $object2, $object2_copy);

// these tests check the various methods for applying tags to an object
$t->diag('various methods for applying tags');
$object = _create_object();
$object->addTag('toto');
$object_tags = $object->getTags();
$t->ok((count($object_tags) == 1) && ($object_tags['toto'] == 'toto'), 'one tag can be added alone.');

$object->addTag('titi,tutu');
$object_tags = $object->getTags();
$t->ok((count($object_tags) == 3) && $object->hasTag('tutu') && $object->hasTag('titi'), 'tags can be added with a comma-separated string.');
$t->ok($object->hasTag('titi, tutu'), 'comma-separated strings are divided into several tags.');

$object = _create_object();
$object->addTag('titi
tutu');
$object_tags = $object->getTags();
$t->ok((count($object_tags) == 2) && $object->hasTag('titi') && $object->hasTag('tutu'), 'tags can be added using line breaks as separators.');
$t->ok($object->hasTag('titi
tutu'), 'line-breaks-separated strings are divided into several tags.');

$object = _create_object();
$object->addTag('titi

tutu');
$object_tags = $object->getTags();
$t->ok((count($object_tags) == 2) && $object->hasTag('titi') && $object->hasTag('tutu'), 'when adding tags using line breaks as separators, remove blank lines.');

$object = _create_object();
$object->addTag(array('titi', 'tutu'));
$object_tags = $object->getTags();
$t->ok((count($object_tags) == 2) && $object->hasTag('tutu') && $object->hasTag('titi'), 'tags can be added with an array.');

$object->setTags('wallace, gromit');
$object_tags = $object->getTags();
$t->ok((count($object_tags) == 2) && $object->hasTag('wallace') && $object->hasTag('gromit'), 'tags can be set directly using setTags().');

unset($object);

// these tests check for the tagging removal on object deletion

// clean the database
Doctrine_Query::create()->delete()->from('Tag')->execute();
Doctrine_Query::create()->delete()->from('Tagging')->execute();
Doctrine_Query::create()->delete()->from(TEST_CLASS)->execute();
Doctrine_Query::create()->delete()->from(TEST_CLASS_2)->execute();

$t->diag('taggings removal on objects deletion');
$object1 = _create_object();
$object1->addTag('tag2,tag3,tag1,tag4,tag5,tag6');
$object1->save();

$object2 = _create_object();
$object2->addTag('tag4,tag7,tag8');
$object2->save();

$object2->delete();

$tags = Doctrine::getTable('Tag')->getAllTagNameWithCount();
$t->ok(isset($tags['tag4']) && !isset($tags['tag7']), 'the taggings associated to one object are deleted when this object is deleted.');

// these tests check for TagPeer methods (tag clouds generation)

// clean the database
Doctrine_Query::create()->delete()->from('Tag')->execute();
Doctrine_Query::create()->delete()->from('Tagging')->execute();
Doctrine_Query::create()->delete()->from(TEST_CLASS)->execute();
Doctrine_Query::create()->delete()->from(TEST_CLASS_2)->execute();

$t->diag('tag clouds');
$object1 = _create_object();
$object1->addTag('tag2,tag3,tag1,tag4,tag5,tag6');
$object1->save();

$object2 = _create_object();
$object2->addTag('tag1,tag3,tag4,tag7');
$object2->save();

$object3 = _create_object();
$object3->addTag('tag2,tag3,tag7,tag8');
$object3->save();

$object4 = _create_object();
$object4->addTag('tag3');
$object4->save();

$object5 = _create_object();
$object5->addTag('tag1,tag3,tag7');
$object5->save();

// getAllTagName() test
$result = Doctrine::getTable('Tag')->getAllTagName();
$t->ok($result == array('tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6', 'tag7', 'tag8'), 'all tags can be retrieved with getAllTagName().');

// getAllTagNameWithCount() test
$tags = Doctrine::getTable('Tag')->getAllTagNameWithCount();
$t->ok($tags == array('tag1' => 3, 'tag2' => 2, 'tag3' => 5, 'tag4' => 2, 'tag5' => 1, 'tag6' => 1, 'tag7' => 3, 'tag8' => 1), 'all tags can be retrieved with getAllTagName().');

// getPopulars() test
$q = Doctrine_Query::create()->limit(3);
$tags = Doctrine::getTable('Tag')->getPopulars($q);
$t->ok(array_keys($tags) == array('tag1', 'tag3', 'tag7'), 'most popular tags can be retrieved with getPopulars().');
$t->ok($tags['tag3'] >= $tags['tag1'], 'getPopulars() preserves tag importance.');

// getRelatedTags() test
$tags = Doctrine::getTable('Tag')->getRelatedTags('tag8');
$t->ok(array_keys($tags) == array('tag2', 'tag3', 'tag7'), 'related tags can be retrieved with getRelatedTags().');

$tags = Doctrine::getTable('Tag')->getRelatedTags('tag2', array('limit' => 1));
$t->ok(array_keys($tags) == array('tag3'), 'when a limit is set, only most popular related tags are returned by getRelatedTags().');

// getRelatedTags() test
$tags = Doctrine::getTable('Tag')->getRelatedTags('tag7');
$t->ok(array_keys($tags) == array('tag1', 'tag2', 'tag3', 'tag4', 'tag8'), 'getRelatedTags() aggregates tags from different objects.');

// getRelatedTags() test
$tags = Doctrine::getTable('Tag')->getRelatedTags(array('tag2', 'tag7'));
$t->ok(array_keys($tags) == array('tag3', 'tag8'), 'getRelatedTags() can retrieve tags related to an array of tags.');

// getRelatedTags() test
$tags = Doctrine::getTable('Tag')->getRelatedTags('tag2,tag7');
$t->ok(array_keys($tags) == array('tag3', 'tag8'), 'getRelatedTags() also accepts a coma-separated string.');

// getObjectTaggedWith() tests
$object_2_1 = _create_object_2();
$object_2_1->addTag('tag1,tag3,tag7');
$object_2_1->save();

$object_2_2 = _create_object_2();
$object_2_2->addTag('tag2,tag7');
$object_2_2->save();

$tagged_with_tag4 = Doctrine::getTable('Tag')->getObjectTaggedWith('tag4');
$t->ok(count($tagged_with_tag4) == 2, 'getObjectTaggedWith() returns objects tagged with one specific tag.');

$tagged_with_tag7 = Doctrine::getTable('Tag')->getObjectTaggedWith('tag7');
$t->ok(count($tagged_with_tag7) == 5, 'getObjectTaggedWith() can return several object types.');

$tagged_with_tag17 = Doctrine::getTable('Tag')->getObjectTaggedWith(array('tag1', 'tag7'));
$t->ok(count($tagged_with_tag17) == 3, 'getObjectTaggedWith() returns objects tagged with several specific tags.');

$tagged_with_tag127 = Doctrine::getTable('Tag')->getObjectTaggedWith('tag1, tag2, tag7',
                                             array('nb_common_tags' => 2));
$t->ok(count($tagged_with_tag127) == 6, 'the "nb_common_tags" option of getObjectTaggedWith() returns objects tagged with a certain number of tags within a set of specific tags.');

// these tests check the preloadTags() method
Taggable::preloadTags($tagged_with_tag17);
$nb_tags = 0;

foreach ($tagged_with_tag17 as $tmp_object)
{
  $nb_tags += count($tmp_object->getTags());
}

$t->ok($nb_tags === 10, 'preloadTags() preloads the tags of the objects.');

// these tests check the isTaggable() method
$t->diag('detecting if a model is taggable or not');

$t->ok(TaggableToolkit::isTaggable(TEST_CLASS) === true, 'it is possible to tell if a model is taggable from its name.');

$object = _create_object();
$t->ok(TaggableToolkit::isTaggable($object) === true, 'it is possible to tell if a model is taggable from one of its instances.');
$t->ok(TaggableToolkit::isTaggable(TEST_NON_TAGGABLE_CLASS) === false, TEST_NON_TAGGABLE_CLASS.' is not taggable, and that is fine.');

// clean the database
Doctrine_Query::create()->delete()->from('Tag')->execute();
Doctrine_Query::create()->delete()->from('Tagging')->execute();
Doctrine_Query::create()->delete()->from(TEST_CLASS)->execute();
Doctrine_Query::create()->delete()->from(TEST_CLASS_2)->execute();

// these tests check for the application of triple tags
$t->diag('applying triple tagging');

$t->ok(TaggableToolkit::extractTriple('ns:key=value') === array('ns:key=value', 'ns', 'key', 'value'), 'triple extracted successfully.');
$t->ok(TaggableToolkit::extractTriple('ns:key') === array('ns:key', null, null, null), 'ns:key is not a triple.');
$t->ok(TaggableToolkit::extractTriple('ns') === array('ns', null, null, null), 'ns is not a triple.');

$object = _create_object();
$object->addTag('tutu');
$object->save();

$object = _create_object();
$object->addTag('ns:key=value');
$object->addTag('ns:key=tutu');
$object->addTag('ns:key=titi');
$object->addTag('ns:key=toto');
$object->save();

$object_tags = $object->getTags();
$t->ok($object->hasTag('ns:key=value'), 'object has triple tag');

$tag = Doctrine::getTable('Tag')->findOrCreateByTagname('ns:key=value');
$t->ok($tag->getIsTriple(), 'a triple tag created from a string is identified as a triple.');

$tag = Doctrine::getTable('Tag')->findOrCreateByTagname('tutu');
$t->ok(!$tag->getIsTriple(), 'a non tripled tag created from a string is not identified as a triple.');

// these tests check the retrieval of the tags of one object, based on
// triple-tags constraints
$t->diag('retrieving triple tags, and extracting only parts of it');

$object = _create_object();
$object->addTag('geo:lat=50.7');
$object->addTag('geo:long=6.1');
$object->addTag('de:city=Aachen');
$object->addTag('fr:city=Aix la Chapelle');
$object->addTag('en:city=Aix Chapel');
$object->save();

// get all the tags
$tags = $object->getTags();
$t->ok(count($tags) == 5, 'The addTags() method permits to create triple tags, that can be retrieved using getTags().');

$id = $object->getPrimaryKey();
$object = Doctrine::getTable(TEST_CLASS)->findOneById($id);
$tags = $object->getTags();
$t->ok(count($tags) == 5, 'The addTags() method permits to create triple tags, that can be retrieved using getTags(), even when saved.');

// get all the informations in the "geo" namespace
$tags = $object->getTags(array('is_triple' => true,
                               'namespace' => 'geo',
                               'return'    => 'value'));
$t->ok(count($tags) == 2, 'The getTags() method permits to select triple tags in one specific namespace.');

// get all the values of the triple tags for which the key is "city", whatever
// the namespace
$tags = $object->getTags(array('is_triple' => true,
                               'key'       => 'city',
                               'return'    => 'value'));
$t->ok(count($tags) == 3, 'The getTags() method permits to select triple tags for one specific key.');

$object2 = _create_object();
$object2->addTag('geo:lat=48.8');
$object2->addTag('geo:long=2.4');
$object2->addTag('de:city=Paris');
$object2->addTag('fr:city=Paris');
$object2->addTag('en:city=Paris');
$object2->save();

// get all the values of the triple tags for which the key is "city", whatever
// the namespace
$tags = $object2->getTags(array('is_triple' => true,
                                'key'       => 'city',
                                'return'    => 'value'));
$t->ok(count($tags) == 1, 'When selecting only the values of triple tags of one object, there is no duplicate.');

$ns = $object2->getTags(array('is_triple' => true,
                              'return'    => 'namespace'));
$t->ok(count($ns) == 4, 'The method getTags() permit to select only the names of the namespaces of the tags attached to one object.');

// these tests check for TagPeer triple tags specific methods (tag clouds generation)
sfConfig::set('app_sfDoctrineActAsTaggablePlugin_triple_distinct', false);
$t->diag('querying triple tagging');

$result = Doctrine::getTable('Tag')->getAllTagName(null, array('triple' => true));
$t->ok(in_array('ns:key=value', $result), 'triple tags are returned when searching for triples only.');
$t->ok(!in_array('tutu', $result), 'ordinary tags are not returned when searching for triples only.');

$result = Doctrine::getTable('Tag')->getAllTagName(null, array('triple' => false));
$t->ok(in_array('tutu', $result), 'normal tags are returned when searching for ordinary ones only.');
$t->ok(!in_array('ns:key=value', $result), 'triple tags are not returned when searching for normal ones.');

// these tests the search of specific triple tags parts
$t->diag('searching for specific parts of triple');

$result = Doctrine::getTable('Tag')->getAllTagName(null, array('triple' => true, 'namespace' => 'ns'));
$t->ok($result === array('ns:key=value', 'ns:key=tutu', 'ns:key=titi', 'ns:key=toto'), 'it is possible to search for triple tags by namespace.');

$result = Doctrine::getTable('Tag')->getAllTagName(null, array('triple' => true, 'key' => 'key'));
$t->ok($result === array('ns:key=value', 'ns:key=tutu', 'ns:key=titi', 'ns:key=toto'), 'it is possible to search for triple tags by key.');

$result = Doctrine::getTable('Tag')->getAllTagName(null, array('triple' => true, 'value' => 'tutu'));
$t->ok($result === array('ns:key=tutu'), 'it is possible to search for triple tags by value.');

$objects_triple = Doctrine::getTable('Tag')->getObjectTaggedWith(array(), array('namespace' => 'ns', 'model' => TEST_CLASS));
$t->ok(count($objects_triple) == 1, 'it is possible to retrieve objects tagged with certain triple tags.');

// clean the database
Doctrine_Query::create()->delete()->from('Tag')->execute();
Doctrine_Query::create()->delete()->from('Tagging')->execute();
Doctrine_Query::create()->delete()->from(TEST_CLASS)->execute();
Doctrine_Query::create()->delete()->from(TEST_CLASS_2)->execute();

// these tests check for the behavior of the triple tags when the plugin is set
// up so that namespace:key is a unique key
sfConfig::set('app_sfDoctrineActAsTaggablePlugin_triple_distinct', true);
$t->diag('querying triple tagging');

$object = _create_object();
$object->addTag('tutu');
$object->save();

$object = _create_object();
$object->addTag('ns:key=value');
$object->addTag('ns:key=tutu');
$object->addTag('ns:key=titi');
$object->addTag('ns:second_key=toto');
$object->save();

$tags_triple = Doctrine::getTable('Tag')->getAllTagName(null, array('triple' => true, 'namespace' => 'ns'));
$t->ok(count($tags_triple) == 2, 'it is possible to set up the plugin so that namespace:key is a unique key.');

$object2 = _create_object();
$object2->addTag('ns:key=value');
$object2->addTag('ns:second_key=toto');
$object2->save();

$tags_triple = Doctrine::getTable('Tag')->getAllTagName(null, array('triple' => true, 'namespace' => 'ns'));
$t->ok(count($tags_triple) == 3, 'it is possible to apply triple tags to various objects when the plugin is set up so that namespace:key is a unique key.');

// test object creation
function _create_object()
{
  $classname = TEST_CLASS;

  if (!class_exists($classname))
  {
    throw new Exception(sprintf('Unknow class "%s"', $classname));
  }

  return new $classname();
}

// second type of test object creation
function _create_object_2()
{
  $classname = TEST_CLASS_2;

  if (!class_exists($classname))
  {
    throw new Exception(sprintf('Unknow class "%s"', $classname));
  }

  return new $classname();
}

// second type of test object creation
function _create_object_not_taggable()
{
  $classname = TEST_NON_TAGGABLE_CLASS;

  if (!class_exists($classname))
  {
    throw new Exception(sprintf('Unknow class "%s"', $classname));
  }

  return new $classname();
}


text:
package org.basex.query.util.regex;

/**
 * A character range.
 *
 * @author BaseX Team 2005-15, BSD License
 * @author Leo Woerteler
 */
public final class CharRange extends RegExp {
  /** Left character. */
  private final int left;
  /** Right character. */
  private final int right;

  /**
   * Constructor.
   * @param left left character
   * @param right right character
   */
  public CharRange(final int left, final int right) {
    this.left = left;
    this.right = right;
  }

  @Override
  void toRegEx(final StringBuilder sb) {
    sb.append(Escape.escape(left)).append('-').append(Escape.escape(right));
  }
}