JOOMLA中国
  • Joomla中国首页
  • 社区
  • 教程
  • 应用市场
  • B计划
Joomla! Framework TM
  • Namespace
  • Class
  • Tree
  • Deprecated

Namespaces

  • Composer
    • Autoload
  • Joomla
    • Application
      • Cli
        • Output
          • Processor
      • Web
    • Data
    • DI
      • Exception
    • Event
    • Filter
    • Input
    • Ldap
    • Registry
      • Format
    • Session
      • Storage
    • String
    • Uri
    • Utilities
  • None
  • PasswordCompat
    • binary
  • PHP
  • Psr
    • Log
  • Symfony
    • Component
      • Yaml
        • Exception
    • Polyfill
      • Util

Classes

  • CallbackFilterIterator
  • ComposerAutoloaderInit205c915b9c7d3e718e7c95793ee67ffe
  • easyparse
  • EasyPeasyICS
  • FOFAutoloaderComponent
  • FOFAutoloaderFof
  • FOFConfigDomainDispatcher
  • FOFConfigDomainTables
  • FOFConfigDomainViews
  • FOFConfigProvider
  • FOFController
  • FOFDatabase
  • FOFDatabaseDriver
  • FOFDatabaseDriverJoomla
  • FOFDatabaseDriverMysql
  • FOFDatabaseDriverMysqli
  • FOFDatabaseDriverOracle
  • FOFDatabaseDriverPdo
  • FOFDatabaseDriverPdomysql
  • FOFDatabaseDriverPostgresql
  • FOFDatabaseDriverSqlazure
  • FOFDatabaseDriverSqlite
  • FOFDatabaseDriverSqlsrv
  • FOFDatabaseFactory
  • FOFDatabaseInstaller
  • FOFDatabaseIterator
  • FOFDatabaseIteratorAzure
  • FOFDatabaseIteratorMysql
  • FOFDatabaseIteratorMysqli
  • FOFDatabaseIteratorOracle
  • FOFDatabaseIteratorPdo
  • FOFDatabaseIteratorPdomysql
  • FOFDatabaseIteratorPostgresql
  • FOFDatabaseIteratorSqlite
  • FOFDatabaseIteratorSqlsrv
  • FOFDatabaseQuery
  • FOFDatabaseQueryElement
  • FOFDatabaseQueryMysql
  • FOFDatabaseQueryMysqli
  • FOFDatabaseQueryOracle
  • FOFDatabaseQueryPdo
  • FOFDatabaseQueryPdomysql
  • FOFDatabaseQueryPostgresql
  • FOFDatabaseQuerySqlazure
  • FOFDatabaseQuerySqlite
  • FOFDatabaseQuerySqlsrv
  • FOFDispatcher
  • FOFDownload
  • FOFDownloadAdapterAbstract
  • FOFDownloadAdapterCurl
  • FOFDownloadAdapterFopen
  • FOFEncryptAes
  • FOFEncryptAesAbstract
  • FOFEncryptAesMcrypt
  • FOFEncryptAesOpenssl
  • FOFEncryptBase32
  • FOFEncryptRandval
  • FOFEncryptTotp
  • FOFForm
  • FOFFormFieldAccesslevel
  • FOFFormFieldActions
  • FOFFormFieldButton
  • FOFFormFieldCachehandler
  • FOFFormFieldCalendar
  • FOFFormFieldCaptcha
  • FOFFormFieldCheckbox
  • FOFFormFieldCheckboxes
  • FOFFormFieldComponents
  • FOFFormFieldEditor
  • FOFFormFieldEmail
  • FOFFormFieldGroupedbutton
  • FOFFormFieldGroupedlist
  • FOFFormFieldHidden
  • FOFFormFieldImage
  • FOFFormFieldImagelist
  • FOFFormFieldInteger
  • FOFFormFieldLanguage
  • FOFFormFieldList
  • FOFFormFieldMedia
  • FOFFormFieldModel
  • FOFFormFieldOrdering
  • FOFFormFieldPassword
  • FOFFormFieldPlugins
  • FOFFormFieldPublished
  • FOFFormFieldRadio
  • FOFFormFieldRelation
  • FOFFormFieldRules
  • FOFFormFieldSelectrow
  • FOFFormFieldSessionhandler
  • FOFFormFieldSpacer
  • FOFFormFieldSql
  • FOFFormFieldTag
  • FOFFormFieldTel
  • FOFFormFieldText
  • FOFFormFieldTextarea
  • FOFFormFieldTimezone
  • FOFFormFieldTitle
  • FOFFormFieldUrl
  • FOFFormFieldUser
  • FOFFormFieldUsergroup
  • FOFFormHeader
  • FOFFormHeaderAccesslevel
  • FOFFormHeaderField
  • FOFFormHeaderFielddate
  • FOFFormHeaderFieldfilterable
  • FOFFormHeaderFieldsearchable
  • FOFFormHeaderFieldselectable
  • FOFFormHeaderFieldsql
  • FOFFormHeaderFilterdate
  • FOFFormHeaderFilterfilterable
  • FOFFormHeaderFiltersearchable
  • FOFFormHeaderFilterselectable
  • FOFFormHeaderFiltersql
  • FOFFormHeaderLanguage
  • FOFFormHeaderModel
  • FOFFormHeaderOrdering
  • FOFFormHeaderPublished
  • FOFFormHeaderRowselect
  • FOFFormHelper
  • FOFHalDocument
  • FOFHalLink
  • FOFHalLinks
  • FOFHalRenderJson
  • FOFInflector
  • FOFInput
  • FOFIntegrationJoomlaFilesystem
  • FOFIntegrationJoomlaPlatform
  • FOFLayoutFile
  • FOFLayoutHelper
  • FOFLess
  • FOFLessFormatterClassic
  • FOFLessFormatterCompressed
  • FOFLessFormatterJoomla
  • FOFLessFormatterLessjs
  • FOFLessParser
  • FOFModel
  • FOFModelBehavior
  • FOFModelBehaviorAccess
  • FOFModelBehaviorEmptynonzero
  • FOFModelBehaviorEnabled
  • FOFModelBehaviorFilters
  • FOFModelBehaviorLanguage
  • FOFModelBehaviorPrivate
  • FOFModelDispatcherBehavior
  • FOFModelField
  • FOFModelFieldBoolean
  • FOFModelFieldDate
  • FOFModelFieldNumber
  • FOFModelFieldText
  • FOFPlatform
  • FOFPlatformFilesystem
  • FOFQueryAbstract
  • FOFRenderAbstract
  • FOFRenderJoomla
  • FOFRenderJoomla3
  • FOFRenderStrapper
  • FOFStringUtils
  • FOFTable
  • FOFTableBehavior
  • FOFTableBehaviorAssets
  • FOFTableBehaviorContenthistory
  • FOFTableBehaviorTags
  • FOFTableDispatcherBehavior
  • FOFTableNested
  • FOFTableRelations
  • FOFTemplateUtils
  • FOFToolbar
  • FOFUtilsArray
  • FOFUtilsCacheCleaner
  • FOFUtilsConfigHelper
  • FOFUtilsFilescheck
  • FOFUtilsIniParser
  • FOFUtilsInstallscript
  • FOFUtilsIp
  • FOFUtilsObject
  • FOFUtilsObservableDispatcher
  • FOFUtilsObservableEvent
  • FOFUtilsPhpfunc
  • FOFUtilsTimer
  • FOFUtilsUpdate
  • FOFUtilsUpdateCollection
  • FOFUtilsUpdateExtension
  • FOFUtilsUpdateJoomla
  • FOFView
  • FOFViewCsv
  • FOFViewForm
  • FOFViewHtml
  • FOFViewJson
  • FOFViewRaw
  • idna_convert
  • JAccess
  • JAccessRule
  • JAccessRules
  • JAccessWrapperAccess
  • JAdapter
  • JAdapterInstance
  • JApplication
  • JApplicationAdministrator
  • JApplicationBase
  • JApplicationCli
  • JApplicationCms
  • JApplicationDaemon
  • JApplicationHelper
  • JApplicationSite
  • JApplicationWeb
  • JApplicationWebRouter
  • JApplicationWebRouterBase
  • JApplicationWebRouterRest
  • JArchive
  • JArchiveBzip2
  • JArchiveGzip
  • JArchiveTar
  • JArchiveWrapperArchive
  • JArchiveZip
  • JArrayHelper
  • JAssociationExtensionHelper
  • JAuthentication
  • JAuthenticationHelper
  • JAuthenticationResponse
  • JBrowser
  • JBuffer
  • JButton
  • JCache
  • JCacheController
  • JCacheControllerCallback
  • JCacheControllerOutput
  • JCacheControllerPage
  • JCacheControllerView
  • JCacheStorage
  • JCacheStorageApc
  • JCacheStorageApcu
  • JCacheStorageCachelite
  • JCacheStorageFile
  • JCacheStorageHelper
  • JCacheStorageMemcache
  • JCacheStorageMemcached
  • JCacheStorageRedis
  • JCacheStorageWincache
  • JCacheStorageXcache
  • JCaptcha
  • JCategories
  • JCategoryNode
  • JClassLoader
  • JCli
  • JClientFtp
  • JClientHelper
  • JClientLdap
  • JClientWrapperHelper
  • JComponentHelper
  • JComponentRecord
  • JComponentRouterBase
  • JComponentRouterLegacy
  • JComponentRouterRulesMenu
  • JComponentRouterRulesNomenu
  • JComponentRouterRulesStandard
  • JComponentRouterView
  • JComponentRouterViewconfiguration
  • JControllerAdmin
  • JControllerBase
  • JControllerForm
  • JControllerLegacy
  • JCrypt
  • JCryptCipher3Des
  • JCryptCipherBlowfish
  • JCryptCipherCrypto
  • JCryptCipherMcrypt
  • JCryptCipherRijndael256
  • JCryptCipherSimple
  • JCryptKey
  • JCryptPasswordSimple
  • JDaemon
  • JDatabase
  • JDatabaseDriver
  • JDatabaseDriverMysql
  • JDatabaseDriverMysqli
  • JDatabaseDriverOracle
  • JDatabaseDriverPdo
  • JDatabaseDriverPdomysql
  • JDatabaseDriverPostgresql
  • JDatabaseDriverSqlazure
  • JDatabaseDriverSqlite
  • JDatabaseDriverSqlsrv
  • JDatabaseExporter
  • JDatabaseExporterMysql
  • JDatabaseExporterMysqli
  • JDatabaseExporterPdomysql
  • JDatabaseExporterPostgresql
  • JDatabaseFactory
  • JDatabaseImporter
  • JDatabaseImporterMysql
  • JDatabaseImporterMysqli
  • JDatabaseImporterPdomysql
  • JDatabaseImporterPostgresql
  • JDatabaseInterface
  • JDatabaseIterator
  • JDatabaseIteratorMysql
  • JDatabaseIteratorMysqli
  • JDatabaseIteratorOracle
  • JDatabaseIteratorPdo
  • JDatabaseIteratorPdomysql
  • JDatabaseIteratorPostgresql
  • JDatabaseIteratorSqlazure
  • JDatabaseIteratorSqlite
  • JDatabaseIteratorSqlsrv
  • JDatabaseMysql
  • JDatabaseMysqli
  • JDatabaseQuery
  • JDatabaseQueryElement
  • JDatabaseQueryLimitable
  • JDatabaseQueryMysql
  • JDatabaseQueryMysqli
  • JDatabaseQueryOracle
  • JDatabaseQueryPdo
  • JDatabaseQueryPdomysql
  • JDatabaseQueryPostgresql
  • JDatabaseQueryPreparable
  • JDatabaseQuerySqlazure
  • JDatabaseQuerySqlite
  • JDatabaseQuerySqlsrv
  • JDatabaseSqlazure
  • JDatabaseSqlsrv
  • JDate
  • JDispatcher
  • JDocument
  • JDocumentError
  • JDocumentFeed
  • JDocumentHtml
  • JDocumentImage
  • JDocumentJson
  • JDocumentOpensearch
  • JDocumentRaw
  • JDocumentRenderer
  • JDocumentRendererAtom
  • JDocumentRendererComponent
  • JDocumentRendererFeedAtom
  • JDocumentRendererFeedRss
  • JDocumentRendererHead
  • JDocumentRendererHtmlComponent
  • JDocumentRendererHtmlHead
  • JDocumentRendererHtmlMessage
  • JDocumentRendererHtmlModule
  • JDocumentRendererHtmlModules
  • JDocumentRendererMessage
  • JDocumentRendererModule
  • JDocumentRendererModules
  • JDocumentRendererRSS
  • JDocumentXml
  • JEditor
  • JError
  • JErrorPage
  • JEvent
  • JEventDispatcher
  • JExtension
  • JFacebook
  • JFacebookAlbum
  • JFacebookCheckin
  • JFacebookComment
  • JFacebookEvent
  • JFacebookGroup
  • JFacebookLink
  • JFacebookNote
  • JFacebookOAuth
  • JFacebookObject
  • JFacebookPhoto
  • JFacebookPost
  • JFacebookStatus
  • JFacebookUser
  • JFacebookVideo
  • JFactory
  • JFeed
  • JFeedEnclosure
  • JFeedEntry
  • JFeedFactory
  • JFeedImage
  • JFeedItem
  • JFeedLink
  • JFeedParser
  • JFeedParserAtom
  • JFeedParserRss
  • JFeedParserRssItunes
  • JFeedParserRssMedia
  • JFeedPerson
  • JFile
  • JFilesystemHelper
  • JFilesystemPatcher
  • JFilesystemWrapperFile
  • JFilesystemWrapperFolder
  • JFilesystemWrapperPath
  • JFilterInput
  • JFilterOutput
  • JFilterWrapperOutput
  • JFolder
  • JForm
  • JFormField
  • JFormFieldAccessLevel
  • JFormFieldAliastag
  • JFormFieldAuthor
  • JFormFieldCacheHandler
  • JFormFieldCalendar
  • JFormFieldCaptcha
  • JFormFieldCategory
  • JFormFieldCheckbox
  • JFormFieldCheckboxes
  • JFormFieldChromeStyle
  • JFormFieldColor
  • JFormFieldCombo
  • JFormFieldComponentlayout
  • JFormFieldComponents
  • JFormFieldContenthistory
  • JFormFieldContentlanguage
  • JFormFieldContenttype
  • JFormFieldDatabaseConnection
  • JFormFieldEditor
  • JFormFieldEMail
  • JFormFieldFile
  • JFormFieldFileList
  • JFormFieldFolderList
  • JFormFieldFrontend_Language
  • JFormFieldGroupedList
  • JFormFieldHeadertag
  • JFormFieldHelpsite
  • JFormFieldHidden
  • JFormFieldImageList
  • JFormFieldInteger
  • JFormFieldLanguage
  • JFormFieldLastvisitDateRange
  • JFormFieldLimitbox
  • JFormFieldList
  • JFormFieldMedia
  • JFormFieldMenu
  • JFormFieldMenuitem
  • JFormFieldMeter
  • JFormFieldModulelayout
  • JFormFieldModuleOrder
  • JFormFieldModulePosition
  • JFormFieldModuletag
  • JFormFieldNote
  • JFormFieldNumber
  • JFormFieldOrdering
  • JFormFieldPassword
  • JFormFieldPlugin_Status
  • JFormFieldPlugins
  • JFormFieldPredefinedList
  • JFormFieldRadio
  • JFormFieldRange
  • JFormFieldRegistrationDateRange
  • JFormFieldRepeatable
  • JFormFieldRules
  • JFormFieldSessionHandler
  • JFormFieldSpacer
  • JFormFieldSQL
  • JFormFieldStatus
  • JFormFieldSubform
  • JFormFieldTag
  • JFormFieldTel
  • JFormFieldTemplatestyle
  • JFormFieldText
  • JFormFieldTextarea
  • JFormFieldTimezone
  • JFormFieldUrl
  • JFormFieldUser
  • JFormFieldUserActive
  • JFormFieldUsergroup
  • JFormFieldUserGroupList
  • JFormFieldUserState
  • JFormHelper
  • JFormRule
  • JFormRuleBoolean
  • JFormRuleCalendar
  • JFormRuleCaptcha
  • JFormRuleColor
  • JFormRuleEmail
  • JFormRuleEquals
  • JFormRuleNotequals
  • JFormRuleNumber
  • JFormRuleOptions
  • JFormRulePassword
  • JFormRuleRules
  • JFormRuleTel
  • JFormRuleUrl
  • JFormRuleUsername
  • JFormWrapperHelper
  • JFTP
  • JGithub
  • JGithubAccount
  • JGithubCommits
  • JGithubForks
  • JGithubHooks
  • JGithubHttp
  • JGithubMeta
  • JGithubMilestones
  • JGithubObject
  • JGithubPackage
  • JGithubPackageActivity
  • JGithubPackageActivityEvents
  • JGithubPackageActivityNotifications
  • JGithubPackageActivityStarring
  • JGithubPackageActivityWatching
  • JGithubPackageAuthorization
  • JGithubPackageData
  • JGithubPackageDataBlobs
  • JGithubPackageDataCommits
  • JGithubPackageDataRefs
  • JGithubPackageDataTags
  • JGithubPackageDataTrees
  • JGithubPackageGists
  • JGithubPackageGistsComments
  • JGithubPackageGitignore
  • JGithubPackageIssues
  • JGithubPackageIssuesAssignees
  • JGithubPackageIssuesComments
  • JGithubPackageIssuesEvents
  • JGithubPackageIssuesLabels
  • JGithubPackageIssuesMilestones
  • JGithubPackageMarkdown
  • JGithubPackageOrgs
  • JGithubPackageOrgsMembers
  • JGithubPackageOrgsTeams
  • JGithubPackagePulls
  • JGithubPackagePullsComments
  • JGithubPackageRepositories
  • JGithubPackageRepositoriesCollaborators
  • JGithubPackageRepositoriesComments
  • JGithubPackageRepositoriesCommits
  • JGithubPackageRepositoriesContents
  • JGithubPackageRepositoriesDownloads
  • JGithubPackageRepositoriesForks
  • JGithubPackageRepositoriesHooks
  • JGithubPackageRepositoriesKeys
  • JGithubPackageRepositoriesMerging
  • JGithubPackageRepositoriesStatistics
  • JGithubPackageRepositoriesStatuses
  • JGithubPackageSearch
  • JGithubPackageUsers
  • JGithubPackageUsersEmails
  • JGithubPackageUsersFollowers
  • JGithubPackageUsersKeys
  • JGithubRefs
  • JGithubStatuses
  • JGoogle
  • JGoogleAuth
  • JGoogleAuthOauth2
  • JGoogleData
  • JGoogleDataAdsense
  • JGoogleDataCalendar
  • JGoogleDataPicasa
  • JGoogleDataPicasaAlbum
  • JGoogleDataPicasaPhoto
  • JGoogleDataPlus
  • JGoogleDataPlusActivities
  • JGoogleDataPlusComments
  • JGoogleDataPlusPeople
  • JGoogleEmbed
  • JGoogleEmbedAnalytics
  • JGoogleEmbedMaps
  • JGrid
  • JHelp
  • JHelper
  • JHelperContent
  • JHelperContenthistory
  • JHelperMedia
  • JHelperRoute
  • JHelperTags
  • JHelperUsergroups
  • JHtml
  • JHtmlAccess
  • JHtmlActionsDropdown
  • JHtmlBatch
  • JHtmlBehavior
  • JHtmlBootstrap
  • JHtmlCategory
  • JHtmlContent
  • JHtmlContentLanguage
  • JHtmlDate
  • JHtmlDebug
  • JHtmlDropdown
  • JHtmlEmail
  • JHtmlForm
  • JHtmlFormbehavior
  • JHtmlGrid
  • JHtmlIcons
  • JHtmlJGrid
  • JHtmlJquery
  • JHtmlLinks
  • JHtmlList
  • JHtmlMenu
  • JHtmlNumber
  • JHtmlRules
  • JHtmlSearchtools
  • JHtmlSelect
  • JHtmlSidebar
  • JHtmlSliders
  • JHtmlSortablelist
  • JHtmlString
  • JHtmlTabs
  • JHtmlTag
  • JHtmlTel
  • JHtmlUser
  • JHttp
  • JHttpFactory
  • JHttpResponse
  • JHttpTransportCurl
  • JHttpTransportSocket
  • JHttpTransportStream
  • JHttpWrapperFactory
  • JImage
  • JImageFilter
  • JImageFilterBackgroundfill
  • JImageFilterBrightness
  • JImageFilterContrast
  • JImageFilterEdgedetect
  • JImageFilterEmboss
  • JImageFilterGrayscale
  • JImageFilterNegate
  • JImageFilterSketchy
  • JImageFilterSmooth
  • JInput
  • JInputCli
  • JInputCookie
  • JInputFiles
  • JInputJSON
  • JInstaller
  • JInstallerAdapter
  • JInstallerAdapterComponent
  • JInstallerAdapterFile
  • JInstallerAdapterLanguage
  • JInstallerAdapterLibrary
  • JInstallerAdapterModule
  • JInstallerAdapterPackage
  • JInstallerAdapterPlugin
  • JInstallerAdapterTemplate
  • JInstallerComponent
  • JInstallerExtension
  • JInstallerFile
  • JInstallerHelper
  • JInstallerLanguage
  • JInstallerLibrary
  • JInstallerManifest
  • JInstallerManifestLibrary
  • JInstallerManifestPackage
  • JInstallerModule
  • JInstallerPackage
  • JInstallerPlugin
  • JInstallerScript
  • JInstallerTemplate
  • JKeychain
  • JLanguage
  • JLanguageAssociations
  • JLanguageHelper
  • JLanguageMultilang
  • JLanguageStemmer
  • JLanguageStemmerPorteren
  • JLanguageTransliterate
  • JLanguageWrapperHelper
  • JLanguageWrapperText
  • JLanguageWrapperTransliterate
  • JLayoutBase
  • JLayoutFile
  • JLayoutHelper
  • JLDAP
  • JLess
  • JLessFormatterJoomla
  • JLibraryHelper
  • JLinkedin
  • JLinkedinCommunications
  • JLinkedinCompanies
  • JLinkedinGroups
  • JLinkedinJobs
  • JLinkedinOauth
  • JLinkedinObject
  • JLinkedinPeople
  • JLinkedinStream
  • JLoader
  • JLog
  • JLogEntry
  • JLogger
  • JLogLogger
  • JLogLoggerCallback
  • JLogLoggerDatabase
  • JLogLoggerEcho
  • JLogLoggerFormattedtext
  • JLogLoggerMessagequeue
  • JLogLoggerSyslog
  • JLogLoggerW3c
  • JMail
  • JMailHelper
  • JMailWrapperHelper
  • JMediawiki
  • JMediawikiCategories
  • JMediawikiHttp
  • JMediawikiImages
  • JMediawikiLinks
  • JMediawikiObject
  • JMediawikiPages
  • JMediawikiSearch
  • JMediawikiSites
  • JMediawikiUsers
  • JMenu
  • JMenuAdministrator
  • JMenuItem
  • JMenuSite
  • JMicrodata
  • JModelAdmin
  • JModelBase
  • JModelDatabase
  • JModelForm
  • JModelItem
  • JModelLegacy
  • JModelList
  • JModuleHelper
  • JNode
  • JOAuth1Client
  • JOAuth2Client
  • JObject
  • JObservable
  • JObserver
  • JObserverMapper
  • JObserverUpdater
  • JObserverWrapperMapper
  • JOpenSearchImage
  • JOpenSearchUrl
  • JOpenstreetmap
  • JOpenstreetmapChangesets
  • JOpenstreetmapElements
  • JOpenstreetmapGps
  • JOpenstreetmapInfo
  • JOpenstreetmapOauth
  • JOpenstreetmapObject
  • JOpenstreetmapUser
  • JPagination
  • JPaginationObject
  • JPath
  • JPathway
  • JPathwaySite
  • JPlatform
  • JPlugin
  • JPluginHelper
  • JProfiler
  • JRequest
  • JResponse
  • JResponseJson
  • JRoute
  • JRouter
  • JRouterAdministrator
  • JRouterSite
  • JRouteWrapperRoute
  • JRule
  • JRules
  • JSchemaChangeitem
  • JSchemaChangeitemMysql
  • JSchemaChangeitemPostgresql
  • JSchemaChangeitemSqlsrv
  • JSchemaChangeset
  • JSearchHelper
  • JSession
  • JSessionHandlerJoomla
  • JSessionHandlerNative
  • JSessionStorage
  • JSessionStorageApc
  • JSessionStorageDatabase
  • JSessionStorageMemcache
  • JSessionStorageMemcached
  • JSessionStorageNone
  • JSessionStorageWincache
  • JSessionStorageXcache
  • JSimplecrypt
  • JSimplepieFactory
  • JStream
  • JStreamString
  • JString
  • JStringController
  • JStringPunycode
  • JStringWrapperNormalise
  • JStringWrapperPunycode
  • JTable
  • JTableAsset
  • JTableCategory
  • JTableContent
  • JTableContenthistory
  • JTableContenttype
  • JTableCorecontent
  • JTableExtension
  • JTableInterface
  • JTableLanguage
  • JTableMenu
  • JTableMenuType
  • JTableModule
  • JTableNested
  • JTableObserver
  • JTableObserverContenthistory
  • JTableObserverTags
  • JTableSession
  • JTableUcm
  • JTableUpdate
  • JTableUpdatesite
  • JTableUser
  • JTableUsergroup
  • JTableViewlevel
  • JText
  • JToolbar
  • JToolbarButton
  • JToolbarButtonConfirm
  • JToolbarButtonCustom
  • JToolbarButtonHelp
  • JToolbarButtonLink
  • JToolbarButtonPopup
  • JToolbarButtonSeparator
  • JToolbarButtonSlider
  • JToolbarButtonStandard
  • JTree
  • JTwitter
  • JTwitterBlock
  • JTwitterDirectmessages
  • JTwitterFavorites
  • JTwitterFriends
  • JTwitterHelp
  • JTwitterLists
  • JTwitterOAuth
  • JTwitterObject
  • JTwitterPlaces
  • JTwitterProfile
  • JTwittersearch
  • JTwitterStatuses
  • JTwitterTrends
  • JTwitterUsers
  • JUcmBase
  • JUcmContent
  • JUcmType
  • JUpdate
  • JUpdateAdapter
  • JUpdater
  • JUpdaterCollection
  • JUpdaterExtension
  • JUri
  • JUser
  • JUserHelper
  • JUserWrapperHelper
  • JUtility
  • JVersion
  • JViewBase
  • JViewCategories
  • JViewCategory
  • JViewCategoryfeed
  • JViewHtml
  • JViewLegacy
  • JWeb
  • JWebClient
  • JXMLElement
  • lessc
  • lessc_formatter_classic
  • lessc_formatter_compressed
  • lessc_formatter_lessjs
  • lessc_parser
  • lessify
  • Net_IDNA_php4
  • nodecounter
  • ntlm_sasl_client_class
  • PHPMailer
  • PHPMailerOAuth
  • PHPMailerOAuthGoogle
  • POP3
  • SimplePie
  • SimplePie_Author
  • SimplePie_Autoloader
  • SimplePie_Cache
  • SimplePie_Cache_DB
  • SimplePie_Cache_File
  • SimplePie_Cache_Memcache
  • SimplePie_Cache_MySQL
  • SimplePie_Caption
  • SimplePie_Category
  • SimplePie_Content_Type_Sniffer
  • SimplePie_Copyright
  • SimplePie_Core
  • SimplePie_Credit
  • SimplePie_Decode_HTML_Entities
  • SimplePie_Enclosure
  • SimplePie_File
  • SimplePie_gzdecode
  • SimplePie_HTTP_Parser
  • SimplePie_IRI
  • SimplePie_Item
  • SimplePie_Locator
  • SimplePie_Misc
  • SimplePie_Net_IPv6
  • SimplePie_Parse_Date
  • SimplePie_Parser
  • SimplePie_Rating
  • SimplePie_Registry
  • SimplePie_Restriction
  • SimplePie_Sanitize
  • SimplePie_Source
  • SimplePie_XML_Declaration_Parser
  • SMTP
  • tagparse
  • TypeError

Interfaces

  • FOFConfigDomainInterface
  • FOFDatabaseInterface
  • FOFDatabaseQueryLimitable
  • FOFDatabaseQueryPreparable
  • FOFDownloadInterface
  • FOFEncryptAesInterface
  • FOFEncryptRandvalinterface
  • FOFFormField
  • FOFHalRenderInterface
  • FOFPlatformFilesystemInterface
  • FOFPlatformInterface
  • JArchiveExtractable
  • JAssociationExtensionInterface
  • JCacheException
  • JComponentRouterInterface
  • JComponentRouterRulesInterface
  • JController
  • JCryptCipher
  • JCryptPassword
  • JFeedParserNamespace
  • JHttpTransport
  • JLayout
  • JModel
  • JObservableInterface
  • JObserverInterface
  • JObserverUpdaterInterface
  • JSessionHandlerInterface
  • JsonSerializable
  • JUcm
  • JView
  • SimplePie_Cache_Base

Exceptions

  • Error
  • JAccessExceptionNotallowed
  • JCacheExceptionConnecting
  • JCacheExceptionUnsupported
  • JComponentExceptionMissing
  • JDatabaseException
  • JDatabaseExceptionConnecting
  • JDatabaseExceptionExecuting
  • JDatabaseExceptionUnsupported
  • JException
  • JSessionExceptionUnsupported
  • LogException
  • phpmailerException
  • SimplePie_Exception

Constants

  • JERROR_CALLBACK_NOT_CALLABLE
  • JERROR_ILLEGAL_MODE
  • JERROR_ILLEGAL_OPTIONS
  • JREQUEST_ALLOWHTML
  • JREQUEST_ALLOWRAW
  • JREQUEST_NOTRIM
  • JROUTER_MODE_RAW
  • JROUTER_MODE_SEF

Functions

  • __autoload
  • array_column
  • boolval
  • composerRequire205c915b9c7d3e718e7c95793ee67ffe
  • gzopen
  • gzseek
  • gztell
  • hash_equals
  • hash_pbkdf2
  • HTMLFilter
  • jexit
  • jimport
  • json_last_error_msg
  • ldap_escape
  • password_get_info
  • password_hash
  • password_needs_rehash
  • password_verify
  • PHPMailerAutoload
  • random_bytes
  • random_int
  • RandomCompat_intval
  • RandomCompat_strlen
  • RandomCompat_substr
  • tln_body2div
  • tln_casenormalize
  • tln_deent
  • tln_defang
  • tln_findnxreg
  • tln_findnxstr
  • tln_fixatts
  • tln_fixstyle
  • tln_fixurl
  • tln_getnxtag
  • tln_sanitize
  • tln_skipspace
  • tln_tagprint
  • tln_unspace
  • utf8_accents_to_ascii
  • utf8_bad_explain
  • utf8_bad_find
  • utf8_bad_findall
  • utf8_bad_identify
  • utf8_bad_replace
  • utf8_bad_strip
  • utf8_byte_position
  • utf8_compliant
  • utf8_from_unicode
  • utf8_ireplace
  • utf8_is_ascii
  • utf8_is_ascii_ctrl
  • utf8_is_valid
  • utf8_is_word_chars
  • utf8_locate_current_chr
  • utf8_locate_next_chr
  • utf8_ltrim
  • utf8_ord
  • utf8_rtrim
  • utf8_specials_pattern
  • utf8_str_pad
  • utf8_str_split
  • utf8_strcasecmp
  • utf8_strcspn
  • utf8_strip_ascii_ctrl
  • utf8_strip_non_ascii
  • utf8_strip_non_ascii_ctrl
  • utf8_strip_specials
  • utf8_stristr
  • utf8_strlen
  • utf8_strpos
  • utf8_strrev
  • utf8_strrpos
  • utf8_strspn
  • utf8_strtolower
  • utf8_strtoupper
  • utf8_substr
  • utf8_substr_replace
  • utf8_to_unicode
  • utf8_trim
  • utf8_ucfirst
  • utf8_ucwords
  • utf8_ucwords_callback
   1 <?php
   2 /**
   3  * @package     FrameworkOnFramework
   4  * @subpackage  less
   5  * @copyright   Copyright (C) 2010-2016 Nicholas K. Dionysopoulos / Akeeba Ltd. All rights reserved.
   6  * @license     GNU General Public License version 2 or later; see LICENSE.txt
   7  */
   8 // Protect from unauthorized access
   9 defined('FOF_INCLUDED') or die;
  10 
  11 /**
  12  * This class is taken near verbatim (changes marked with **FOF** comment markers) from:
  13  *
  14  * lessphp v0.3.9
  15  * http://leafo.net/lessphp
  16  *
  17  * LESS css compiler, adapted from http://lesscss.org
  18  *
  19  * Copyright 2012, Leaf Corcoran <leafot@gmail.com>
  20  * Licensed under MIT or GPLv3, see LICENSE
  21  *
  22  * THIS IS THIRD PARTY CODE. Code comments are mostly useless placeholders to
  23  * stop phpcs from complaining...
  24  *
  25  * @package  FrameworkOnFramework
  26  * @since    2.0
  27  */
  28 class FOFLess
  29 {
  30     public static $VERSION = "v0.3.9";
  31 
  32     protected static $TRUE = array("keyword", "true");
  33 
  34     protected static $FALSE = array("keyword", "false");
  35 
  36     protected $libFunctions = array();
  37 
  38     protected $registeredVars = array();
  39 
  40     protected $preserveComments = false;
  41 
  42     /**
  43      * Prefix of abstract properties
  44      *
  45      * @var  string
  46      */
  47     public $vPrefix = '@';
  48 
  49     /**
  50      * Prefix of abstract blocks
  51      *
  52      * @var  string
  53      */
  54     public $mPrefix = '$';
  55 
  56     public $parentSelector = '&';
  57 
  58     public $importDisabled = false;
  59 
  60     public $importDir = '';
  61 
  62     protected $numberPrecision = null;
  63 
  64     /**
  65      * Set to the parser that generated the current line when compiling
  66      * so we know how to create error messages
  67      *
  68      * @var  FOFLessParser
  69      */
  70     protected $sourceParser = null;
  71 
  72     protected $sourceLoc = null;
  73 
  74     public static $defaultValue = array("keyword", "");
  75 
  76     /**
  77      * Uniquely identify imports
  78      *
  79      * @var  integer
  80      */
  81     protected static $nextImportId = 0;
  82 
  83     /**
  84      * Attempts to find the path of an import url, returns null for css files
  85      *
  86      * @param   string  $url  The URL of the import
  87      *
  88      * @return  string|null
  89      */
  90     protected function findImport($url)
  91     {
  92         foreach ((array) $this->importDir as $dir)
  93         {
  94             $full = $dir . (substr($dir, -1) != '/' ? '/' : '') . $url;
  95 
  96             if ($this->fileExists($file = $full . '.less') || $this->fileExists($file = $full))
  97             {
  98                 return $file;
  99             }
 100         }
 101 
 102         return null;
 103     }
 104 
 105     /**
 106      * Does file $name exists? It's a simple proxy to JFile for now
 107      *
 108      * @param   string  $name  The file we check for existence
 109      *
 110      * @return  boolean
 111      */
 112     protected function fileExists($name)
 113     {
 114         /** FOF - BEGIN CHANGE * */
 115         return FOFPlatform::getInstance()->getIntegrationObject('filesystem')->fileExists($name);
 116         /** FOF - END CHANGE * */
 117     }
 118 
 119     /**
 120      * Compresslist
 121      *
 122      * @param   array   $items  Items
 123      * @param   string  $delim  Delimiter
 124      *
 125      * @return  array
 126      */
 127     public static function compressList($items, $delim)
 128     {
 129         if (!isset($items[1]) && isset($items[0]))
 130         {
 131             return $items[0];
 132         }
 133         else
 134         {
 135             return array('list', $delim, $items);
 136         }
 137     }
 138 
 139     /**
 140      * Quote for regular expression
 141      *
 142      * @param   string  $what  What to quote
 143      *
 144      * @return  string  Quoted string
 145      */
 146     public static function preg_quote($what)
 147     {
 148         return preg_quote($what, '/');
 149     }
 150 
 151     /**
 152      * Try import
 153      *
 154      * @param   string     $importPath   Import path
 155      * @param   stdObject  $parentBlock  Parent block
 156      * @param   string     $out          Out
 157      *
 158      * @return  boolean
 159      */
 160     protected function tryImport($importPath, $parentBlock, $out)
 161     {
 162         if ($importPath[0] == "function" && $importPath[1] == "url")
 163         {
 164             $importPath = $this->flattenList($importPath[2]);
 165         }
 166 
 167         $str = $this->coerceString($importPath);
 168 
 169         if ($str === null)
 170         {
 171             return false;
 172         }
 173 
 174         $url = $this->compileValue($this->lib_e($str));
 175 
 176         // Don't import if it ends in css
 177         if (substr_compare($url, '.css', -4, 4) === 0)
 178         {
 179             return false;
 180         }
 181 
 182         $realPath = $this->findImport($url);
 183 
 184         if ($realPath === null)
 185         {
 186             return false;
 187         }
 188 
 189         if ($this->importDisabled)
 190         {
 191             return array(false, "/* import disabled */");
 192         }
 193 
 194         $this->addParsedFile($realPath);
 195         $parser = $this->makeParser($realPath);
 196         $root = $parser->parse(file_get_contents($realPath));
 197 
 198         // Set the parents of all the block props
 199         foreach ($root->props as $prop)
 200         {
 201             if ($prop[0] == "block")
 202             {
 203                 $prop[1]->parent = $parentBlock;
 204             }
 205         }
 206 
 207         /**
 208          * Copy mixins into scope, set their parents, bring blocks from import
 209          * into current block
 210          * TODO: need to mark the source parser these came from this file
 211          */
 212         foreach ($root->children as $childName => $child)
 213         {
 214             if (isset($parentBlock->children[$childName]))
 215             {
 216                 $parentBlock->children[$childName] = array_merge(
 217                     $parentBlock->children[$childName], $child
 218                 );
 219             }
 220             else
 221             {
 222                 $parentBlock->children[$childName] = $child;
 223             }
 224         }
 225 
 226         $pi = pathinfo($realPath);
 227         $dir = $pi["dirname"];
 228 
 229         list($top, $bottom) = $this->sortProps($root->props, true);
 230         $this->compileImportedProps($top, $parentBlock, $out, $parser, $dir);
 231 
 232         return array(true, $bottom, $parser, $dir);
 233     }
 234 
 235     /**
 236      * Compile Imported Props
 237      *
 238      * @param   array          $props         Props
 239      * @param   stdClass       $block         Block
 240      * @param   string         $out           Out
 241      * @param   FOFLessParser  $sourceParser  Source parser
 242      * @param   string         $importDir     Import dir
 243      *
 244      * @return  void
 245      */
 246     protected function compileImportedProps($props, $block, $out, $sourceParser, $importDir)
 247     {
 248         $oldSourceParser = $this->sourceParser;
 249 
 250         $oldImport = $this->importDir;
 251 
 252         // TODO: this is because the importDir api is stupid
 253         $this->importDir = (array) $this->importDir;
 254         array_unshift($this->importDir, $importDir);
 255 
 256         foreach ($props as $prop)
 257         {
 258             $this->compileProp($prop, $block, $out);
 259         }
 260 
 261         $this->importDir = $oldImport;
 262         $this->sourceParser = $oldSourceParser;
 263     }
 264 
 265     /**
 266      * Recursively compiles a block.
 267      *
 268      * A block is analogous to a CSS block in most cases. A single LESS document
 269      * is encapsulated in a block when parsed, but it does not have parent tags
 270      * so all of it's children appear on the root level when compiled.
 271      *
 272      * Blocks are made up of props and children.
 273      *
 274      * Props are property instructions, array tuples which describe an action
 275      * to be taken, eg. write a property, set a variable, mixin a block.
 276      *
 277      * The children of a block are just all the blocks that are defined within.
 278      * This is used to look up mixins when performing a mixin.
 279      *
 280      * Compiling the block involves pushing a fresh environment on the stack,
 281      * and iterating through the props, compiling each one.
 282      *
 283      * @param   stdClass  $block  Block
 284      *
 285      * @see  FOFLess::compileProp()
 286      *
 287      * @return  void
 288      */
 289     protected function compileBlock($block)
 290     {
 291         switch ($block->type)
 292         {
 293             case "root":
 294                 $this->compileRoot($block);
 295                 break;
 296             case null:
 297                 $this->compileCSSBlock($block);
 298                 break;
 299             case "media":
 300                 $this->compileMedia($block);
 301                 break;
 302             case "directive":
 303                 $name = "@" . $block->name;
 304 
 305                 if (!empty($block->value))
 306                 {
 307                     $name .= " " . $this->compileValue($this->reduce($block->value));
 308                 }
 309 
 310                 $this->compileNestedBlock($block, array($name));
 311                 break;
 312             default:
 313                 $this->throwError("unknown block type: $block->type\n");
 314         }
 315     }
 316 
 317     /**
 318      * Compile CSS block
 319      *
 320      * @param   stdClass  $block  Block to compile
 321      *
 322      * @return  void
 323      */
 324     protected function compileCSSBlock($block)
 325     {
 326         $env = $this->pushEnv();
 327 
 328         $selectors = $this->compileSelectors($block->tags);
 329         $env->selectors = $this->multiplySelectors($selectors);
 330         $out = $this->makeOutputBlock(null, $env->selectors);
 331 
 332         $this->scope->children[] = $out;
 333         $this->compileProps($block, $out);
 334 
 335         // Mixins carry scope with them!
 336         $block->scope = $env;
 337         $this->popEnv();
 338     }
 339 
 340     /**
 341      * Compile media
 342      *
 343      * @param   stdClass  $media  Media
 344      *
 345      * @return  void
 346      */
 347     protected function compileMedia($media)
 348     {
 349         $env = $this->pushEnv($media);
 350         $parentScope = $this->mediaParent($this->scope);
 351 
 352         $query = $this->compileMediaQuery($this->multiplyMedia($env));
 353 
 354         $this->scope = $this->makeOutputBlock($media->type, array($query));
 355         $parentScope->children[] = $this->scope;
 356 
 357         $this->compileProps($media, $this->scope);
 358 
 359         if (count($this->scope->lines) > 0)
 360         {
 361             $orphanSelelectors = $this->findClosestSelectors();
 362 
 363             if (!is_null($orphanSelelectors))
 364             {
 365                 $orphan = $this->makeOutputBlock(null, $orphanSelelectors);
 366                 $orphan->lines = $this->scope->lines;
 367                 array_unshift($this->scope->children, $orphan);
 368                 $this->scope->lines = array();
 369             }
 370         }
 371 
 372         $this->scope = $this->scope->parent;
 373         $this->popEnv();
 374     }
 375 
 376     /**
 377      * Media parent
 378      *
 379      * @param   stdClass  $scope  Scope
 380      *
 381      * @return  stdClass
 382      */
 383     protected function mediaParent($scope)
 384     {
 385         while (!empty($scope->parent))
 386         {
 387             if (!empty($scope->type) && $scope->type != "media")
 388             {
 389                 break;
 390             }
 391 
 392             $scope = $scope->parent;
 393         }
 394 
 395         return $scope;
 396     }
 397 
 398     /**
 399      * Compile nested block
 400      *
 401      * @param   stdClass  $block      Block
 402      * @param   array     $selectors  Selectors
 403      *
 404      * @return  void
 405      */
 406     protected function compileNestedBlock($block, $selectors)
 407     {
 408         $this->pushEnv($block);
 409         $this->scope = $this->makeOutputBlock($block->type, $selectors);
 410         $this->scope->parent->children[] = $this->scope;
 411 
 412         $this->compileProps($block, $this->scope);
 413 
 414         $this->scope = $this->scope->parent;
 415         $this->popEnv();
 416     }
 417 
 418     /**
 419      * Compile root
 420      *
 421      * @param   stdClass  $root  Root
 422      *
 423      * @return  void
 424      */
 425     protected function compileRoot($root)
 426     {
 427         $this->pushEnv();
 428         $this->scope = $this->makeOutputBlock($root->type);
 429         $this->compileProps($root, $this->scope);
 430         $this->popEnv();
 431     }
 432 
 433     /**
 434      * Compile props
 435      *
 436      * @param   type  $block  Something
 437      * @param   type  $out    Something
 438      *
 439      * @return  void
 440      */
 441     protected function compileProps($block, $out)
 442     {
 443         foreach ($this->sortProps($block->props) as $prop)
 444         {
 445             $this->compileProp($prop, $block, $out);
 446         }
 447     }
 448 
 449     /**
 450      * Sort props
 451      *
 452      * @param   type  $props  X
 453      * @param   type  $split  X
 454      *
 455      * @return  type
 456      */
 457     protected function sortProps($props, $split = false)
 458     {
 459         $vars    = array();
 460         $imports = array();
 461         $other   = array();
 462 
 463         foreach ($props as $prop)
 464         {
 465             switch ($prop[0])
 466             {
 467                 case "assign":
 468                     if (isset($prop[1][0]) && $prop[1][0] == $this->vPrefix)
 469                     {
 470                         $vars[] = $prop;
 471                     }
 472                     else
 473                     {
 474                         $other[] = $prop;
 475                     }
 476                     break;
 477                 case "import":
 478                     $id        = self::$nextImportId++;
 479                     $prop[]    = $id;
 480                     $imports[] = $prop;
 481                     $other[]   = array("import_mixin", $id);
 482                     break;
 483                 default:
 484                     $other[] = $prop;
 485             }
 486         }
 487 
 488         if ($split)
 489         {
 490             return array(array_merge($vars, $imports), $other);
 491         }
 492         else
 493         {
 494             return array_merge($vars, $imports, $other);
 495         }
 496     }
 497 
 498     /**
 499      * Compile media query
 500      *
 501      * @param   type  $queries  Queries
 502      *
 503      * @return  string
 504      */
 505     protected function compileMediaQuery($queries)
 506     {
 507         $compiledQueries = array();
 508 
 509         foreach ($queries as $query)
 510         {
 511             $parts = array();
 512 
 513             foreach ($query as $q)
 514             {
 515                 switch ($q[0])
 516                 {
 517                     case "mediaType":
 518                         $parts[] = implode(" ", array_slice($q, 1));
 519                         break;
 520                     case "mediaExp":
 521                         if (isset($q[2]))
 522                         {
 523                             $parts[] = "($q[1]: " .
 524                                 $this->compileValue($this->reduce($q[2])) . ")";
 525                         }
 526                         else
 527                         {
 528                             $parts[] = "($q[1])";
 529                         }
 530                         break;
 531                     case "variable":
 532                         $parts[] = $this->compileValue($this->reduce($q));
 533                         break;
 534                 }
 535             }
 536 
 537             if (count($parts) > 0)
 538             {
 539                 $compiledQueries[] = implode(" and ", $parts);
 540             }
 541         }
 542 
 543         $out = "@media";
 544 
 545         if (!empty($parts))
 546         {
 547             $out .= " " .
 548                 implode($this->formatter->selectorSeparator, $compiledQueries);
 549         }
 550 
 551         return $out;
 552     }
 553 
 554     /**
 555      * Multiply media
 556      *
 557      * @param   type  $env           X
 558      * @param   type  $childQueries  X
 559      *
 560      * @return  type
 561      */
 562     protected function multiplyMedia($env, $childQueries = null)
 563     {
 564         if (is_null($env)
 565             || !empty($env->block->type)
 566             && $env->block->type != "media")
 567         {
 568             return $childQueries;
 569         }
 570 
 571         // Plain old block, skip
 572         if (empty($env->block->type))
 573         {
 574             return $this->multiplyMedia($env->parent, $childQueries);
 575         }
 576 
 577         $out = array();
 578         $queries = $env->block->queries;
 579 
 580         if (is_null($childQueries))
 581         {
 582             $out = $queries;
 583         }
 584         else
 585         {
 586             foreach ($queries as $parent)
 587             {
 588                 foreach ($childQueries as $child)
 589                 {
 590                     $out[] = array_merge($parent, $child);
 591                 }
 592             }
 593         }
 594 
 595         return $this->multiplyMedia($env->parent, $out);
 596     }
 597 
 598     /**
 599      * Expand parent selectors
 600      *
 601      * @param   type  &$tag     Tag
 602      * @param   type  $replace  Replace
 603      *
 604      * @return  type
 605      */
 606     protected function expandParentSelectors(&$tag, $replace)
 607     {
 608         $parts = explode("$&$", $tag);
 609         $count = 0;
 610 
 611         foreach ($parts as &$part)
 612         {
 613             $part = str_replace($this->parentSelector, $replace, $part, $c);
 614             $count += $c;
 615         }
 616 
 617         $tag = implode($this->parentSelector, $parts);
 618 
 619         return $count;
 620     }
 621 
 622     /**
 623      * Find closest selectors
 624      *
 625      * @return  array
 626      */
 627     protected function findClosestSelectors()
 628     {
 629         $env = $this->env;
 630         $selectors = null;
 631 
 632         while ($env !== null)
 633         {
 634             if (isset($env->selectors))
 635             {
 636                 $selectors = $env->selectors;
 637                 break;
 638             }
 639 
 640             $env = $env->parent;
 641         }
 642 
 643         return $selectors;
 644     }
 645 
 646     /**
 647      * Multiply $selectors against the nearest selectors in env
 648      *
 649      * @param   array  $selectors  The selectors
 650      *
 651      * @return  array
 652      */
 653     protected function multiplySelectors($selectors)
 654     {
 655         // Find parent selectors
 656 
 657         $parentSelectors = $this->findClosestSelectors();
 658 
 659         if (is_null($parentSelectors))
 660         {
 661             // Kill parent reference in top level selector
 662             foreach ($selectors as &$s)
 663             {
 664                 $this->expandParentSelectors($s, "");
 665             }
 666 
 667             return $selectors;
 668         }
 669 
 670         $out = array();
 671 
 672         foreach ($parentSelectors as $parent)
 673         {
 674             foreach ($selectors as $child)
 675             {
 676                 $count = $this->expandParentSelectors($child, $parent);
 677 
 678                 // Don't prepend the parent tag if & was used
 679                 if ($count > 0)
 680                 {
 681                     $out[] = trim($child);
 682                 }
 683                 else
 684                 {
 685                     $out[] = trim($parent . ' ' . $child);
 686                 }
 687             }
 688         }
 689 
 690         return $out;
 691     }
 692 
 693     /**
 694      * Reduces selector expressions
 695      *
 696      * @param   array  $selectors  The selector expressions
 697      *
 698      * @return  array
 699      */
 700     protected function compileSelectors($selectors)
 701     {
 702         $out = array();
 703 
 704         foreach ($selectors as $s)
 705         {
 706             if (is_array($s))
 707             {
 708                 list(, $value) = $s;
 709                 $out[] = trim($this->compileValue($this->reduce($value)));
 710             }
 711             else
 712             {
 713                 $out[] = $s;
 714             }
 715         }
 716 
 717         return $out;
 718     }
 719 
 720     /**
 721      * Equality check
 722      *
 723      * @param   mixed  $left   Left operand
 724      * @param   mixed  $right  Right operand
 725      *
 726      * @return  boolean  True if equal
 727      */
 728     protected function eq($left, $right)
 729     {
 730         return $left == $right;
 731     }
 732 
 733     /**
 734      * Pattern match
 735      *
 736      * @param   type  $block        X
 737      * @param   type  $callingArgs  X
 738      *
 739      * @return  boolean
 740      */
 741     protected function patternMatch($block, $callingArgs)
 742     {
 743         /**
 744          * Match the guards if it has them
 745          * any one of the groups must have all its guards pass for a match
 746          */
 747         if (!empty($block->guards))
 748         {
 749             $groupPassed = false;
 750 
 751             foreach ($block->guards as $guardGroup)
 752             {
 753                 foreach ($guardGroup as $guard)
 754                 {
 755                     $this->pushEnv();
 756                     $this->zipSetArgs($block->args, $callingArgs);
 757 
 758                     $negate = false;
 759 
 760                     if ($guard[0] == "negate")
 761                     {
 762                         $guard = $guard[1];
 763                         $negate = true;
 764                     }
 765 
 766                     $passed = $this->reduce($guard) == self::$TRUE;
 767 
 768                     if ($negate)
 769                     {
 770                         $passed = !$passed;
 771                     }
 772 
 773                     $this->popEnv();
 774 
 775                     if ($passed)
 776                     {
 777                         $groupPassed = true;
 778                     }
 779                     else
 780                     {
 781                         $groupPassed = false;
 782                         break;
 783                     }
 784                 }
 785 
 786                 if ($groupPassed)
 787                 {
 788                     break;
 789                 }
 790             }
 791 
 792             if (!$groupPassed)
 793             {
 794                 return false;
 795             }
 796         }
 797 
 798         $numCalling = count($callingArgs);
 799 
 800         if (empty($block->args))
 801         {
 802             return $block->isVararg || $numCalling == 0;
 803         }
 804 
 805         // No args
 806         $i = -1;
 807 
 808         // Try to match by arity or by argument literal
 809         foreach ($block->args as $i => $arg)
 810         {
 811             switch ($arg[0])
 812             {
 813                 case "lit":
 814                     if (empty($callingArgs[$i]) || !$this->eq($arg[1], $callingArgs[$i]))
 815                     {
 816                         return false;
 817                     }
 818                     break;
 819                 case "arg":
 820                     // No arg and no default value
 821                     if (!isset($callingArgs[$i]) && !isset($arg[2]))
 822                     {
 823                         return false;
 824                     }
 825                     break;
 826                 case "rest":
 827                     // Rest can be empty
 828                     $i--;
 829                     break 2;
 830             }
 831         }
 832 
 833         if ($block->isVararg)
 834         {
 835             // Not having enough is handled above
 836             return true;
 837         }
 838         else
 839         {
 840             $numMatched = $i + 1;
 841 
 842             // Greater than becuase default values always match
 843             return $numMatched >= $numCalling;
 844         }
 845     }
 846 
 847     /**
 848      * Pattern match all
 849      *
 850      * @param   type  $blocks       X
 851      * @param   type  $callingArgs  X
 852      *
 853      * @return  type
 854      */
 855     protected function patternMatchAll($blocks, $callingArgs)
 856     {
 857         $matches = null;
 858 
 859         foreach ($blocks as $block)
 860         {
 861             if ($this->patternMatch($block, $callingArgs))
 862             {
 863                 $matches[] = $block;
 864             }
 865         }
 866 
 867         return $matches;
 868     }
 869 
 870     /**
 871      * Attempt to find blocks matched by path and args
 872      *
 873      * @param   array   $searchIn  Block to search in
 874      * @param   string  $path      The path to search for
 875      * @param   array   $args      Arguments
 876      * @param   array   $seen      Your guess is as good as mine; that's third party code
 877      *
 878      * @return  null
 879      */
 880     protected function findBlocks($searchIn, $path, $args, $seen = array())
 881     {
 882         if ($searchIn == null)
 883         {
 884             return null;
 885         }
 886 
 887         if (isset($seen[$searchIn->id]))
 888         {
 889             return null;
 890         }
 891 
 892         $seen[$searchIn->id] = true;
 893 
 894         $name = $path[0];
 895 
 896         if (isset($searchIn->children[$name]))
 897         {
 898             $blocks = $searchIn->children[$name];
 899 
 900             if (count($path) == 1)
 901             {
 902                 $matches = $this->patternMatchAll($blocks, $args);
 903 
 904                 if (!empty($matches))
 905                 {
 906                     // This will return all blocks that match in the closest
 907                     // scope that has any matching block, like lessjs
 908                     return $matches;
 909                 }
 910             }
 911             else
 912             {
 913                 $matches = array();
 914 
 915                 foreach ($blocks as $subBlock)
 916                 {
 917                     $subMatches = $this->findBlocks($subBlock, array_slice($path, 1), $args, $seen);
 918 
 919                     if (!is_null($subMatches))
 920                     {
 921                         foreach ($subMatches as $sm)
 922                         {
 923                             $matches[] = $sm;
 924                         }
 925                     }
 926                 }
 927 
 928                 return count($matches) > 0 ? $matches : null;
 929             }
 930         }
 931 
 932         if ($searchIn->parent === $searchIn)
 933         {
 934             return null;
 935         }
 936 
 937         return $this->findBlocks($searchIn->parent, $path, $args, $seen);
 938     }
 939 
 940     /**
 941      * Sets all argument names in $args to either the default value
 942      * or the one passed in through $values
 943      *
 944      * @param   array  $args    Arguments
 945      * @param   array  $values  Values
 946      *
 947      * @return  void
 948      */
 949     protected function zipSetArgs($args, $values)
 950     {
 951         $i = 0;
 952         $assignedValues = array();
 953 
 954         foreach ($args as $a)
 955         {
 956             if ($a[0] == "arg")
 957             {
 958                 if ($i < count($values) && !is_null($values[$i]))
 959                 {
 960                     $value = $values[$i];
 961                 }
 962                 elseif (isset($a[2]))
 963                 {
 964                     $value = $a[2];
 965                 }
 966                 else
 967                 {
 968                     $value = null;
 969                 }
 970 
 971                 $value = $this->reduce($value);
 972                 $this->set($a[1], $value);
 973                 $assignedValues[] = $value;
 974             }
 975 
 976             $i++;
 977         }
 978 
 979         // Check for a rest
 980         $last = end($args);
 981 
 982         if ($last[0] == "rest")
 983         {
 984             $rest = array_slice($values, count($args) - 1);
 985             $this->set($last[1], $this->reduce(array("list", " ", $rest)));
 986         }
 987 
 988         $this->env->arguments = $assignedValues;
 989     }
 990 
 991     /**
 992      * Compile a prop and update $lines or $blocks appropriately
 993      *
 994      * @param   array     $prop   Prop
 995      * @param   stdClass  $block  Block
 996      * @param   string    $out    Out
 997      *
 998      * @return  void
 999      */
1000     protected function compileProp($prop, $block, $out)
1001     {
1002         // Set error position context
1003         $this->sourceLoc = isset($prop[-1]) ? $prop[-1] : -1;
1004 
1005         switch ($prop[0])
1006         {
1007             case 'assign':
1008                 list(, $name, $value) = $prop;
1009 
1010                 if ($name[0] == $this->vPrefix)
1011                 {
1012                     $this->set($name, $value);
1013                 }
1014                 else
1015                 {
1016                     $out->lines[] = $this->formatter->property($name, $this->compileValue($this->reduce($value)));
1017                 }
1018                 break;
1019             case 'block':
1020                 list(, $child) = $prop;
1021                 $this->compileBlock($child);
1022                 break;
1023             case 'mixin':
1024                 list(, $path, $args, $suffix) = $prop;
1025 
1026                 $args = array_map(array($this, "reduce"), (array) $args);
1027                 $mixins = $this->findBlocks($block, $path, $args);
1028 
1029                 if ($mixins === null)
1030                 {
1031                     // Throw error here??
1032                     break;
1033                 }
1034 
1035                 foreach ($mixins as $mixin)
1036                 {
1037                     $haveScope = false;
1038 
1039                     if (isset($mixin->parent->scope))
1040                     {
1041                         $haveScope = true;
1042                         $mixinParentEnv = $this->pushEnv();
1043                         $mixinParentEnv->storeParent = $mixin->parent->scope;
1044                     }
1045 
1046                     $haveArgs = false;
1047 
1048                     if (isset($mixin->args))
1049                     {
1050                         $haveArgs = true;
1051                         $this->pushEnv();
1052                         $this->zipSetArgs($mixin->args, $args);
1053                     }
1054 
1055                     $oldParent = $mixin->parent;
1056 
1057                     if ($mixin != $block)
1058                     {
1059                         $mixin->parent = $block;
1060                     }
1061 
1062                     foreach ($this->sortProps($mixin->props) as $subProp)
1063                     {
1064                         if ($suffix !== null
1065                             && $subProp[0] == "assign"
1066                             && is_string($subProp[1])
1067                             && $subProp[1]{0} != $this->vPrefix)
1068                         {
1069                             $subProp[2] = array(
1070                                 'list', ' ',
1071                                 array($subProp[2], array('keyword', $suffix))
1072                             );
1073                         }
1074 
1075                         $this->compileProp($subProp, $mixin, $out);
1076                     }
1077 
1078                     $mixin->parent = $oldParent;
1079 
1080                     if ($haveArgs)
1081                     {
1082                         $this->popEnv();
1083                     }
1084 
1085                     if ($haveScope)
1086                     {
1087                         $this->popEnv();
1088                     }
1089                 }
1090 
1091                 break;
1092             case 'raw':
1093                 $out->lines[] = $prop[1];
1094                 break;
1095             case "directive":
1096                 list(, $name, $value) = $prop;
1097                 $out->lines[] = "@$name " . $this->compileValue($this->reduce($value)) . ';';
1098                 break;
1099             case "comment":
1100                 $out->lines[] = $prop[1];
1101                 break;
1102             case "import";
1103                 list(, $importPath, $importId) = $prop;
1104                 $importPath = $this->reduce($importPath);
1105 
1106                 if (!isset($this->env->imports))
1107                 {
1108                     $this->env->imports = array();
1109                 }
1110 
1111                 $result = $this->tryImport($importPath, $block, $out);
1112 
1113                 $this->env->imports[$importId] = $result === false ?
1114                     array(false, "@import " . $this->compileValue($importPath) . ";") :
1115                     $result;
1116 
1117                 break;
1118             case "import_mixin":
1119                 list(, $importId) = $prop;
1120                 $import = $this->env->imports[$importId];
1121 
1122                 if ($import[0] === false)
1123                 {
1124                     $out->lines[] = $import[1];
1125                 }
1126                 else
1127                 {
1128                     list(, $bottom, $parser, $importDir) = $import;
1129                     $this->compileImportedProps($bottom, $block, $out, $parser, $importDir);
1130                 }
1131 
1132                 break;
1133             default:
1134                 $this->throwError("unknown op: {$prop[0]}\n");
1135         }
1136     }
1137 
1138     /**
1139      * Compiles a primitive value into a CSS property value.
1140      *
1141      * Values in lessphp are typed by being wrapped in arrays, their format is
1142      * typically:
1143      *
1144      *     array(type, contents [, additional_contents]*)
1145      *
1146      * The input is expected to be reduced. This function will not work on
1147      * things like expressions and variables.
1148      *
1149      * @param   array  $value  Value
1150      *
1151      * @return  void
1152      */
1153     protected function compileValue($value)
1154     {
1155         switch ($value[0])
1156         {
1157             case 'list':
1158                 // [1] - delimiter
1159                 // [2] - array of values
1160                 return implode($value[1], array_map(array($this, 'compileValue'), $value[2]));
1161             case 'raw_color':
1162                 if (!empty($this->formatter->compressColors))
1163                 {
1164                     return $this->compileValue($this->coerceColor($value));
1165                 }
1166 
1167                 return $value[1];
1168             case 'keyword':
1169                 // [1] - the keyword
1170                 return $value[1];
1171             case 'number':
1172                 // Format: [1] - the number -- [2] - the unit
1173                 list(, $num, $unit) = $value;
1174 
1175                 if ($this->numberPrecision !== null)
1176                 {
1177                     $num = round($num, $this->numberPrecision);
1178                 }
1179 
1180                 return $num . $unit;
1181             case 'string':
1182                 // [1] - contents of string (includes quotes)
1183                 list(, $delim, $content) = $value;
1184 
1185                 foreach ($content as &$part)
1186                 {
1187                     if (is_array($part))
1188                     {
1189                         $part = $this->compileValue($part);
1190                     }
1191                 }
1192 
1193                 return $delim . implode($content) . $delim;
1194             case 'color':
1195                 /**
1196                  * Format:
1197                  *
1198                  * [1] - red component (either number or a %)
1199                  * [2] - green component
1200                  * [3] - blue component
1201                  * [4] - optional alpha component
1202                  */
1203                 list(, $r, $g, $b) = $value;
1204                 $r = round($r);
1205                 $g = round($g);
1206                 $b = round($b);
1207 
1208                 if (count($value) == 5 && $value[4] != 1)
1209                 {
1210                     // Return an rgba value
1211                     return 'rgba(' . $r . ',' . $g . ',' . $b . ',' . $value[4] . ')';
1212                 }
1213 
1214                 $h = sprintf("#%02x%02x%02x", $r, $g, $b);
1215 
1216                 if (!empty($this->formatter->compressColors))
1217                 {
1218                     // Converting hex color to short notation (e.g. #003399 to #039)
1219                     if ($h[1] === $h[2] && $h[3] === $h[4] && $h[5] === $h[6])
1220                     {
1221                         $h = '#' . $h[1] . $h[3] . $h[5];
1222                     }
1223                 }
1224 
1225                 return $h;
1226 
1227             case 'function':
1228                 list(, $name, $args) = $value;
1229 
1230                 return $name . '(' . $this->compileValue($args) . ')';
1231 
1232             default:
1233                 // Assumed to be unit
1234                 $this->throwError("unknown value type: $value[0]");
1235         }
1236     }
1237 
1238     /**
1239      * Lib is number
1240      *
1241      * @param   type  $value  X
1242      *
1243      * @return  boolean
1244      */
1245     protected function lib_isnumber($value)
1246     {
1247         return $this->toBool($value[0] == "number");
1248     }
1249 
1250     /**
1251      * Lib is string
1252      *
1253      * @param   type  $value  X
1254      *
1255      * @return  boolean
1256      */
1257     protected function lib_isstring($value)
1258     {
1259         return $this->toBool($value[0] == "string");
1260     }
1261 
1262     /**
1263      * Lib is color
1264      *
1265      * @param   type  $value  X
1266      *
1267      * @return  boolean
1268      */
1269     protected function lib_iscolor($value)
1270     {
1271         return $this->toBool($this->coerceColor($value));
1272     }
1273 
1274     /**
1275      * Lib is keyword
1276      *
1277      * @param   type  $value  X
1278      *
1279      * @return  boolean
1280      */
1281     protected function lib_iskeyword($value)
1282     {
1283         return $this->toBool($value[0] == "keyword");
1284     }
1285 
1286     /**
1287      * Lib is pixel
1288      *
1289      * @param   type  $value  X
1290      *
1291      * @return  boolean
1292      */
1293     protected function lib_ispixel($value)
1294     {
1295         return $this->toBool($value[0] == "number" && $value[2] == "px");
1296     }
1297 
1298     /**
1299      * Lib is percentage
1300      *
1301      * @param   type  $value  X
1302      *
1303      * @return  boolean
1304      */
1305     protected function lib_ispercentage($value)
1306     {
1307         return $this->toBool($value[0] == "number" && $value[2] == "%");
1308     }
1309 
1310     /**
1311      * Lib is em
1312      *
1313      * @param   type  $value  X
1314      *
1315      * @return  boolean
1316      */
1317     protected function lib_isem($value)
1318     {
1319         return $this->toBool($value[0] == "number" && $value[2] == "em");
1320     }
1321 
1322     /**
1323      * Lib is rem
1324      *
1325      * @param   type  $value  X
1326      *
1327      * @return  boolean
1328      */
1329     protected function lib_isrem($value)
1330     {
1331         return $this->toBool($value[0] == "number" && $value[2] == "rem");
1332     }
1333 
1334     /**
1335      * LIb rgba hex
1336      *
1337      * @param   type  $color  X
1338      *
1339      * @return  boolean
1340      */
1341     protected function lib_rgbahex($color)
1342     {
1343         $color = $this->coerceColor($color);
1344 
1345         if (is_null($color))
1346         {
1347             $this->throwError("color expected for rgbahex");
1348         }
1349 
1350         return sprintf("#%02x%02x%02x%02x", isset($color[4]) ? $color[4] * 255 : 255, $color[1], $color[2], $color[3]);
1351     }
1352 
1353     /**
1354      * Lib argb
1355      *
1356      * @param   type  $color  X
1357      *
1358      * @return  type
1359      */
1360     protected function lib_argb($color)
1361     {
1362         return $this->lib_rgbahex($color);
1363     }
1364 
1365     /**
1366      * Utility func to unquote a string
1367      *
1368      * @param   string  $arg  Arg
1369      *
1370      * @return  string
1371      */
1372     protected function lib_e($arg)
1373     {
1374         switch ($arg[0])
1375         {
1376             case "list":
1377                 $items = $arg[2];
1378 
1379                 if (isset($items[0]))
1380                 {
1381                     return $this->lib_e($items[0]);
1382                 }
1383 
1384                 return self::$defaultValue;
1385 
1386             case "string":
1387                 $arg[1] = "";
1388 
1389                 return $arg;
1390 
1391             case "keyword":
1392                 return $arg;
1393 
1394             default:
1395                 return array("keyword", $this->compileValue($arg));
1396         }
1397     }
1398 
1399     /**
1400      * Lib sprintf
1401      *
1402      * @param   type  $args  X
1403      *
1404      * @return  type
1405      */
1406     protected function lib__sprintf($args)
1407     {
1408         if ($args[0] != "list")
1409         {
1410             return $args;
1411         }
1412 
1413         $values = $args[2];
1414         $string = array_shift($values);
1415         $template = $this->compileValue($this->lib_e($string));
1416 
1417         $i = 0;
1418 
1419         if (preg_match_all('/%[dsa]/', $template, $m))
1420         {
1421             foreach ($m[0] as $match)
1422             {
1423                 $val = isset($values[$i]) ?
1424                     $this->reduce($values[$i]) : array('keyword', '');
1425 
1426                 // Lessjs compat, renders fully expanded color, not raw color
1427                 if ($color = $this->coerceColor($val))
1428                 {
1429                     $val = $color;
1430                 }
1431 
1432                 $i++;
1433                 $rep = $this->compileValue($this->lib_e($val));
1434                 $template = preg_replace('/' . self::preg_quote($match) . '/', $rep, $template, 1);
1435             }
1436         }
1437 
1438         $d = $string[0] == "string" ? $string[1] : '"';
1439 
1440         return array("string", $d, array($template));
1441     }
1442 
1443     /**
1444      * Lib floor
1445      *
1446      * @param   type  $arg  X
1447      *
1448      * @return  array
1449      */
1450     protected function lib_floor($arg)
1451     {
1452         $value = $this->assertNumber($arg);
1453 
1454         return array("number", floor($value), $arg[2]);
1455     }
1456 
1457     /**
1458      * Lib ceil
1459      *
1460      * @param   type  $arg  X
1461      *
1462      * @return  array
1463      */
1464     protected function lib_ceil($arg)
1465     {
1466         $value = $this->assertNumber($arg);
1467 
1468         return array("number", ceil($value), $arg[2]);
1469     }
1470 
1471     /**
1472      * Lib round
1473      *
1474      * @param   type  $arg  X
1475      *
1476      * @return  array
1477      */
1478     protected function lib_round($arg)
1479     {
1480         $value = $this->assertNumber($arg);
1481 
1482         return array("number", round($value), $arg[2]);
1483     }
1484 
1485     /**
1486      * Lib unit
1487      *
1488      * @param   type  $arg  X
1489      *
1490      * @return  array
1491      */
1492     protected function lib_unit($arg)
1493     {
1494         if ($arg[0] == "list")
1495         {
1496             list($number, $newUnit) = $arg[2];
1497             return array("number", $this->assertNumber($number), $this->compileValue($this->lib_e($newUnit)));
1498         }
1499         else
1500         {
1501             return array("number", $this->assertNumber($arg), "");
1502         }
1503     }
1504 
1505     /**
1506      * Helper function to get arguments for color manipulation functions.
1507      * takes a list that contains a color like thing and a percentage
1508      *
1509      * @param   array  $args  Args
1510      *
1511      * @return  array
1512      */
1513     protected function colorArgs($args)
1514     {
1515         if ($args[0] != 'list' || count($args[2]) < 2)
1516         {
1517             return array(array('color', 0, 0, 0), 0);
1518         }
1519 
1520         list($color, $delta) = $args[2];
1521         $color = $this->assertColor($color);
1522         $delta = floatval($delta[1]);
1523 
1524         return array($color, $delta);
1525     }
1526 
1527     /**
1528      * Lib darken
1529      *
1530      * @param   type  $args  X
1531      *
1532      * @return  type
1533      */
1534     protected function lib_darken($args)
1535     {
1536         list($color, $delta) = $this->colorArgs($args);
1537 
1538         $hsl = $this->toHSL($color);
1539         $hsl[3] = $this->clamp($hsl[3] - $delta, 100);
1540 
1541         return $this->toRGB($hsl);
1542     }
1543 
1544     /**
1545      * Lib lighten
1546      *
1547      * @param   type  $args  X
1548      *
1549      * @return  type
1550      */
1551     protected function lib_lighten($args)
1552     {
1553         list($color, $delta) = $this->colorArgs($args);
1554 
1555         $hsl = $this->toHSL($color);
1556         $hsl[3] = $this->clamp($hsl[3] + $delta, 100);
1557 
1558         return $this->toRGB($hsl);
1559     }
1560 
1561     /**
1562      * Lib saturate
1563      *
1564      * @param   type  $args  X
1565      *
1566      * @return  type
1567      */
1568     protected function lib_saturate($args)
1569     {
1570         list($color, $delta) = $this->colorArgs($args);
1571 
1572         $hsl = $this->toHSL($color);
1573         $hsl[2] = $this->clamp($hsl[2] + $delta, 100);
1574 
1575         return $this->toRGB($hsl);
1576     }
1577 
1578     /**
1579      * Lib desaturate
1580      *
1581      * @param   type  $args  X
1582      *
1583      * @return  type
1584      */
1585     protected function lib_desaturate($args)
1586     {
1587         list($color, $delta) = $this->colorArgs($args);
1588 
1589         $hsl = $this->toHSL($color);
1590         $hsl[2] = $this->clamp($hsl[2] - $delta, 100);
1591 
1592         return $this->toRGB($hsl);
1593     }
1594 
1595     /**
1596      * Lib spin
1597      *
1598      * @param   type  $args  X
1599      *
1600      * @return  type
1601      */
1602     protected function lib_spin($args)
1603     {
1604         list($color, $delta) = $this->colorArgs($args);
1605 
1606         $hsl = $this->toHSL($color);
1607 
1608         $hsl[1] = $hsl[1] + $delta % 360;
1609 
1610         if ($hsl[1] < 0)
1611         {
1612             $hsl[1] += 360;
1613         }
1614 
1615         return $this->toRGB($hsl);
1616     }
1617 
1618     /**
1619      * Lib fadeout
1620      *
1621      * @param   type  $args  X
1622      *
1623      * @return  type
1624      */
1625     protected function lib_fadeout($args)
1626     {
1627         list($color, $delta) = $this->colorArgs($args);
1628         $color[4] = $this->clamp((isset($color[4]) ? $color[4] : 1) - $delta / 100);
1629 
1630         return $color;
1631     }
1632 
1633     /**
1634      * Lib fadein
1635      *
1636      * @param   type  $args  X
1637      *
1638      * @return  type
1639      */
1640     protected function lib_fadein($args)
1641     {
1642         list($color, $delta) = $this->colorArgs($args);
1643         $color[4] = $this->clamp((isset($color[4]) ? $color[4] : 1) + $delta / 100);
1644 
1645         return $color;
1646     }
1647 
1648     /**
1649      * Lib hue
1650      *
1651      * @param   type  $color  X
1652      *
1653      * @return  type
1654      */
1655     protected function lib_hue($color)
1656     {
1657         $hsl = $this->toHSL($this->assertColor($color));
1658 
1659         return round($hsl[1]);
1660     }
1661 
1662     /**
1663      * Lib saturation
1664      *
1665      * @param   type  $color  X
1666      *
1667      * @return  type
1668      */
1669     protected function lib_saturation($color)
1670     {
1671         $hsl = $this->toHSL($this->assertColor($color));
1672 
1673         return round($hsl[2]);
1674     }
1675 
1676     /**
1677      * Lib lightness
1678      *
1679      * @param   type  $color  X
1680      *
1681      * @return  type
1682      */
1683     protected function lib_lightness($color)
1684     {
1685         $hsl = $this->toHSL($this->assertColor($color));
1686 
1687         return round($hsl[3]);
1688     }
1689 
1690     /**
1691      * Get the alpha of a color
1692      * Defaults to 1 for non-colors or colors without an alpha
1693      *
1694      * @param   string  $value  Value
1695      *
1696      * @return  string
1697      */
1698     protected function lib_alpha($value)
1699     {
1700         if (!is_null($color = $this->coerceColor($value)))
1701         {
1702             return isset($color[4]) ? $color[4] : 1;
1703         }
1704     }
1705 
1706     /**
1707      * Set the alpha of the color
1708      *
1709      * @param   array  $args  Args
1710      *
1711      * @return  string
1712      */
1713     protected function lib_fade($args)
1714     {
1715         list($color, $alpha) = $this->colorArgs($args);
1716         $color[4] = $this->clamp($alpha / 100.0);
1717 
1718         return $color;
1719     }
1720 
1721     /**
1722      * Third party code; your guess is as good as mine
1723      *
1724      * @param   array  $arg  Arg
1725      *
1726      * @return  string
1727      */
1728     protected function lib_percentage($arg)
1729     {
1730         $num = $this->assertNumber($arg);
1731 
1732         return array("number", $num * 100, "%");
1733     }
1734 
1735     /**
1736      * mixes two colors by weight
1737      * mix(@color1, @color2, @weight);
1738      * http://sass-lang.com/docs/yardoc/Sass/Script/Functions.html#mix-instance_method
1739      *
1740      * @param   array  $args  Args
1741      *
1742      * @return  string
1743      */
1744     protected function lib_mix($args)
1745     {
1746         if ($args[0] != "list" || count($args[2]) < 3)
1747         {
1748             $this->throwError("mix expects (color1, color2, weight)");
1749         }
1750 
1751         list($first, $second, $weight) = $args[2];
1752         $first = $this->assertColor($first);
1753         $second = $this->assertColor($second);
1754 
1755         $first_a = $this->lib_alpha($first);
1756         $second_a = $this->lib_alpha($second);
1757         $weight = $weight[1] / 100.0;
1758 
1759         $w = $weight * 2 - 1;
1760         $a = $first_a - $second_a;
1761 
1762         $w1 = (($w * $a == -1 ? $w : ($w + $a) / (1 + $w * $a)) + 1) / 2.0;
1763         $w2 = 1.0 - $w1;
1764 
1765         $new = array('color',
1766             $w1 * $first[1] + $w2 * $second[1],
1767             $w1 * $first[2] + $w2 * $second[2],
1768             $w1 * $first[3] + $w2 * $second[3],
1769         );
1770 
1771         if ($first_a != 1.0 || $second_a != 1.0)
1772         {
1773             $new[] = $first_a * $weight + $second_a * ($weight - 1);
1774         }
1775 
1776         return $this->fixColor($new);
1777     }
1778 
1779     /**
1780      * Third party code; your guess is as good as mine
1781      *
1782      * @param   array  $arg  Arg
1783      *
1784      * @return  string
1785      */
1786     protected function lib_contrast($args)
1787     {
1788         if ($args[0] != 'list' || count($args[2]) < 3)
1789         {
1790             return array(array('color', 0, 0, 0), 0);
1791         }
1792 
1793         list($inputColor, $darkColor, $lightColor) = $args[2];
1794 
1795         $inputColor = $this->assertColor($inputColor);
1796         $darkColor = $this->assertColor($darkColor);
1797         $lightColor = $this->assertColor($lightColor);
1798         $hsl = $this->toHSL($inputColor);
1799 
1800         if ($hsl[3] > 50)
1801         {
1802             return $darkColor;
1803         }
1804 
1805         return $lightColor;
1806     }
1807 
1808     /**
1809      * Assert color
1810      *
1811      * @param   type  $value  X
1812      * @param   type  $error  X
1813      *
1814      * @return  type
1815      */
1816     protected function assertColor($value, $error = "expected color value")
1817     {
1818         $color = $this->coerceColor($value);
1819 
1820         if (is_null($color))
1821         {
1822             $this->throwError($error);
1823         }
1824 
1825         return $color;
1826     }
1827 
1828     /**
1829      * Assert number
1830      *
1831      * @param   type  $value  X
1832      * @param   type  $error  X
1833      *
1834      * @return  type
1835      */
1836     protected function assertNumber($value, $error = "expecting number")
1837     {
1838         if ($value[0] == "number")
1839         {
1840             return $value[1];
1841         }
1842 
1843         $this->throwError($error);
1844     }
1845 
1846     /**
1847      * To HSL
1848      *
1849      * @param   type  $color  X
1850      *
1851      * @return  type
1852      */
1853     protected function toHSL($color)
1854     {
1855         if ($color[0] == 'hsl')
1856         {
1857             return $color;
1858         }
1859 
1860         $r = $color[1] / 255;
1861         $g = $color[2] / 255;
1862         $b = $color[3] / 255;
1863 
1864         $min = min($r, $g, $b);
1865         $max = max($r, $g, $b);
1866 
1867         $L = ($min + $max) / 2;
1868 
1869         if ($min == $max)
1870         {
1871             $S = $H = 0;
1872         }
1873         else
1874         {
1875             if ($L < 0.5)
1876             {
1877                 $S = ($max - $min) / ($max + $min);
1878             }
1879             else
1880             {
1881                 $S = ($max - $min) / (2.0 - $max - $min);
1882             }
1883 
1884             if ($r == $max)
1885             {
1886                 $H = ($g - $b) / ($max - $min);
1887             }
1888             elseif ($g == $max)
1889             {
1890                 $H = 2.0 + ($b - $r) / ($max - $min);
1891             }
1892             elseif ($b == $max)
1893             {
1894                 $H = 4.0 + ($r - $g) / ($max - $min);
1895             }
1896         }
1897 
1898         $out = array('hsl',
1899             ($H < 0 ? $H + 6 : $H) * 60,
1900             $S * 100,
1901             $L * 100,
1902         );
1903 
1904         if (count($color) > 4)
1905         {
1906             // Copy alpha
1907             $out[] = $color[4];
1908         }
1909 
1910         return $out;
1911     }
1912 
1913     /**
1914      * To RGB helper
1915      *
1916      * @param   type  $comp   X
1917      * @param   type  $temp1  X
1918      * @param   type  $temp2  X
1919      *
1920      * @return  type
1921      */
1922     protected function toRGB_helper($comp, $temp1, $temp2)
1923     {
1924         if ($comp < 0)
1925         {
1926             $comp += 1.0;
1927         }
1928         elseif ($comp > 1)
1929         {
1930             $comp -= 1.0;
1931         }
1932 
1933         if (6 * $comp < 1)
1934         {
1935             return $temp1 + ($temp2 - $temp1) * 6 * $comp;
1936         }
1937 
1938         if (2 * $comp < 1)
1939         {
1940             return $temp2;
1941         }
1942 
1943         if (3 * $comp < 2)
1944         {
1945             return $temp1 + ($temp2 - $temp1) * ((2 / 3) - $comp) * 6;
1946         }
1947 
1948         return $temp1;
1949     }
1950 
1951     /**
1952      * Converts a hsl array into a color value in rgb.
1953      * Expects H to be in range of 0 to 360, S and L in 0 to 100
1954      *
1955      * @param   type  $color  X
1956      *
1957      * @return  type
1958      */
1959     protected function toRGB($color)
1960     {
1961         if ($color == 'color')
1962         {
1963             return $color;
1964         }
1965 
1966         $H = $color[1] / 360;
1967         $S = $color[2] / 100;
1968         $L = $color[3] / 100;
1969 
1970         if ($S == 0)
1971         {
1972             $r = $g = $b = $L;
1973         }
1974         else
1975         {
1976             $temp2 = $L < 0.5 ?
1977                 $L * (1.0 + $S) :
1978                 $L + $S - $L * $S;
1979 
1980             $temp1 = 2.0 * $L - $temp2;
1981 
1982             $r = $this->toRGB_helper($H + 1 / 3, $temp1, $temp2);
1983             $g = $this->toRGB_helper($H, $temp1, $temp2);
1984             $b = $this->toRGB_helper($H - 1 / 3, $temp1, $temp2);
1985         }
1986 
1987         // $out = array('color', round($r*255), round($g*255), round($b*255));
1988         $out = array('color', $r * 255, $g * 255, $b * 255);
1989 
1990         if (count($color) > 4)
1991         {
1992             // Copy alpha
1993             $out[] = $color[4];
1994         }
1995 
1996         return $out;
1997     }
1998 
1999     /**
2000      * Clamp
2001      *
2002      * @param   type  $v    X
2003      * @param   type  $max  X
2004      * @param   type  $min  X
2005      *
2006      * @return  type
2007      */
2008     protected function clamp($v, $max = 1, $min = 0)
2009     {
2010         return min($max, max($min, $v));
2011     }
2012 
2013     /**
2014      * Convert the rgb, rgba, hsl color literals of function type
2015      * as returned by the parser into values of color type.
2016      *
2017      * @param   type  $func  X
2018      *
2019      * @return  type
2020      */
2021     protected function funcToColor($func)
2022     {
2023         $fname = $func[1];
2024 
2025         if ($func[2][0] != 'list')
2026         {
2027             // Need a list of arguments
2028             return false;
2029         }
2030 
2031         $rawComponents = $func[2][2];
2032 
2033         if ($fname == 'hsl' || $fname == 'hsla')
2034         {
2035             $hsl = array('hsl');
2036             $i = 0;
2037 
2038             foreach ($rawComponents as $c)
2039             {
2040                 $val = $this->reduce($c);
2041                 $val = isset($val[1]) ? floatval($val[1]) : 0;
2042 
2043                 if ($i == 0)
2044                 {
2045                     $clamp = 360;
2046                 }
2047                 elseif ($i < 3)
2048                 {
2049                     $clamp = 100;
2050                 }
2051                 else
2052                 {
2053                     $clamp = 1;
2054                 }
2055 
2056                 $hsl[] = $this->clamp($val, $clamp);
2057                 $i++;
2058             }
2059 
2060             while (count($hsl) < 4)
2061             {
2062                 $hsl[] = 0;
2063             }
2064 
2065             return $this->toRGB($hsl);
2066         }
2067         elseif ($fname == 'rgb' || $fname == 'rgba')
2068         {
2069             $components = array();
2070             $i = 1;
2071 
2072             foreach ($rawComponents as $c)
2073             {
2074                 $c = $this->reduce($c);
2075 
2076                 if ($i < 4)
2077                 {
2078                     if ($c[0] == "number" && $c[2] == "%")
2079                     {
2080                         $components[] = 255 * ($c[1] / 100);
2081                     }
2082                     else
2083                     {
2084                         $components[] = floatval($c[1]);
2085                     }
2086                 }
2087                 elseif ($i == 4)
2088                 {
2089                     if ($c[0] == "number" && $c[2] == "%")
2090                     {
2091                         $components[] = 1.0 * ($c[1] / 100);
2092                     }
2093                     else
2094                     {
2095                         $components[] = floatval($c[1]);
2096                     }
2097                 }
2098                 else
2099                 {
2100                     break;
2101                 }
2102 
2103                 $i++;
2104             }
2105 
2106             while (count($components) < 3)
2107             {
2108                 $components[] = 0;
2109             }
2110 
2111             array_unshift($components, 'color');
2112 
2113             return $this->fixColor($components);
2114         }
2115 
2116         return false;
2117     }
2118 
2119     /**
2120      * Reduce
2121      *
2122      * @param   type  $value          X
2123      * @param   type  $forExpression  X
2124      *
2125      * @return  type
2126      */
2127     protected function reduce($value, $forExpression = false)
2128     {
2129         switch ($value[0])
2130         {
2131             case "interpolate":
2132                 $reduced = $this->reduce($value[1]);
2133                 $var     = $this->compileValue($reduced);
2134                 $res     = $this->reduce(array("variable", $this->vPrefix . $var));
2135 
2136                 if (empty($value[2]))
2137                 {
2138                     $res = $this->lib_e($res);
2139                 }
2140 
2141                 return $res;
2142             case "variable":
2143                 $key = $value[1];
2144                 if (is_array($key))
2145                 {
2146                     $key = $this->reduce($key);
2147                     $key = $this->vPrefix . $this->compileValue($this->lib_e($key));
2148                 }
2149 
2150                 $seen = & $this->env->seenNames;
2151 
2152                 if (!empty($seen[$key]))
2153                 {
2154                     $this->throwError("infinite loop detected: $key");
2155                 }
2156 
2157                 $seen[$key] = true;
2158                 $out = $this->reduce($this->get($key, self::$defaultValue));
2159                 $seen[$key] = false;
2160 
2161                 return $out;
2162             case "list":
2163                 foreach ($value[2] as &$item)
2164                 {
2165                     $item = $this->reduce($item, $forExpression);
2166                 }
2167 
2168                 return $value;
2169             case "expression":
2170                 return $this->evaluate($value);
2171             case "string":
2172                 foreach ($value[2] as &$part)
2173                 {
2174                     if (is_array($part))
2175                     {
2176                         $strip = $part[0] == "variable";
2177                         $part = $this->reduce($part);
2178 
2179                         if ($strip)
2180                         {
2181                             $part = $this->lib_e($part);
2182                         }
2183                     }
2184                 }
2185 
2186                 return $value;
2187             case "escape":
2188                 list(, $inner) = $value;
2189 
2190                 return $this->lib_e($this->reduce($inner));
2191             case "function":
2192                 $color = $this->funcToColor($value);
2193 
2194                 if ($color)
2195                 {
2196                     return $color;
2197                 }
2198 
2199                 list(, $name, $args) = $value;
2200 
2201                 if ($name == "%")
2202                 {
2203                     $name = "_sprintf";
2204                 }
2205 
2206                 $f = isset($this->libFunctions[$name]) ?
2207                     $this->libFunctions[$name] : array($this, 'lib_' . $name);
2208 
2209                 if (is_callable($f))
2210                 {
2211                     if ($args[0] == 'list')
2212                     {
2213                         $args = self::compressList($args[2], $args[1]);
2214                     }
2215 
2216                     $ret = call_user_func($f, $this->reduce($args, true), $this);
2217 
2218                     if (is_null($ret))
2219                     {
2220                         return array("string", "", array(
2221                                 $name, "(", $args, ")"
2222                             ));
2223                     }
2224 
2225                     // Convert to a typed value if the result is a php primitive
2226                     if (is_numeric($ret))
2227                     {
2228                         $ret = array('number', $ret, "");
2229                     }
2230                     elseif (!is_array($ret))
2231                     {
2232                         $ret = array('keyword', $ret);
2233                     }
2234 
2235                     return $ret;
2236                 }
2237 
2238                 // Plain function, reduce args
2239                 $value[2] = $this->reduce($value[2]);
2240 
2241                 return $value;
2242             case "unary":
2243                 list(, $op, $exp) = $value;
2244                 $exp = $this->reduce($exp);
2245 
2246                 if ($exp[0] == "number")
2247                 {
2248                     switch ($op)
2249                     {
2250                         case "+":
2251                             return $exp;
2252                         case "-":
2253                             $exp[1] *= -1;
2254 
2255                             return $exp;
2256                     }
2257                 }
2258 
2259                 return array("string", "", array($op, $exp));
2260         }
2261 
2262         if ($forExpression)
2263         {
2264             switch ($value[0])
2265             {
2266                 case "keyword":
2267                     if ($color = $this->coerceColor($value))
2268                     {
2269                         return $color;
2270                     }
2271                     break;
2272                 case "raw_color":
2273                     return $this->coerceColor($value);
2274             }
2275         }
2276 
2277         return $value;
2278     }
2279 
2280     /**
2281      * Coerce a value for use in color operation
2282      *
2283      * @param   type  $value  X
2284      *
2285      * @return  null
2286      */
2287     protected function coerceColor($value)
2288     {
2289         switch ($value[0])
2290         {
2291             case 'color':
2292                 return $value;
2293             case 'raw_color':
2294                 $c = array("color", 0, 0, 0);
2295                 $colorStr = substr($value[1], 1);
2296                 $num = hexdec($colorStr);
2297                 $width = strlen($colorStr) == 3 ? 16 : 256;
2298 
2299                 for ($i = 3; $i > 0; $i--)
2300                 {
2301                     // It's 3 2 1
2302                     $t = $num % $width;
2303                     $num /= $width;
2304 
2305                     $c[$i] = $t * (256 / $width) + $t * floor(16 / $width);
2306                 }
2307 
2308                 return $c;
2309             case 'keyword':
2310                 $name = $value[1];
2311 
2312                 if (isset(self::$cssColors[$name]))
2313                 {
2314                     $rgba = explode(',', self::$cssColors[$name]);
2315 
2316                     if (isset($rgba[3]))
2317                     {
2318                         return array('color', $rgba[0], $rgba[1], $rgba[2], $rgba[3]);
2319                     }
2320 
2321                     return array('color', $rgba[0], $rgba[1], $rgba[2]);
2322                 }
2323 
2324                 return null;
2325         }
2326     }
2327 
2328     /**
2329      * Make something string like into a string
2330      *
2331      * @param   type  $value  X
2332      *
2333      * @return  null
2334      */
2335     protected function coerceString($value)
2336     {
2337         switch ($value[0])
2338         {
2339             case "string":
2340                 return $value;
2341             case "keyword":
2342                 return array("string", "", array($value[1]));
2343         }
2344 
2345         return null;
2346     }
2347 
2348     /**
2349      * Turn list of length 1 into value type
2350      *
2351      * @param   type  $value  X
2352      *
2353      * @return  type
2354      */
2355     protected function flattenList($value)
2356     {
2357         if ($value[0] == "list" && count($value[2]) == 1)
2358         {
2359             return $this->flattenList($value[2][0]);
2360         }
2361 
2362         return $value;
2363     }
2364 
2365     /**
2366      * To bool
2367      *
2368      * @param   type  $a  X
2369      *
2370      * @return  type
2371      */
2372     protected function toBool($a)
2373     {
2374         if ($a)
2375         {
2376             return self::$TRUE;
2377         }
2378         else
2379         {
2380             return self::$FALSE;
2381         }
2382     }
2383 
2384     /**
2385      * Evaluate an expression
2386      *
2387      * @param   type  $exp  X
2388      *
2389      * @return  type
2390      */
2391     protected function evaluate($exp)
2392     {
2393         list(, $op, $left, $right, $whiteBefore, $whiteAfter) = $exp;
2394 
2395         $left = $this->reduce($left, true);
2396         $right = $this->reduce($right, true);
2397 
2398         if ($leftColor = $this->coerceColor($left))
2399         {
2400             $left = $leftColor;
2401         }
2402 
2403         if ($rightColor = $this->coerceColor($right))
2404         {
2405             $right = $rightColor;
2406         }
2407 
2408         $ltype = $left[0];
2409         $rtype = $right[0];
2410 
2411         // Operators that work on all types
2412         if ($op == "and")
2413         {
2414             return $this->toBool($left == self::$TRUE && $right == self::$TRUE);
2415         }
2416 
2417         if ($op == "=")
2418         {
2419             return $this->toBool($this->eq($left, $right));
2420         }
2421 
2422         if ($op == "+" && !is_null($str = $this->stringConcatenate($left, $right)))
2423         {
2424             return $str;
2425         }
2426 
2427         // Type based operators
2428         $fname = "op_${ltype}_${rtype}";
2429 
2430         if (is_callable(array($this, $fname)))
2431         {
2432             $out = $this->$fname($op, $left, $right);
2433 
2434             if (!is_null($out))
2435             {
2436                 return $out;
2437             }
2438         }
2439 
2440         // Make the expression look it did before being parsed
2441         $paddedOp = $op;
2442 
2443         if ($whiteBefore)
2444         {
2445             $paddedOp = " " . $paddedOp;
2446         }
2447 
2448         if ($whiteAfter)
2449         {
2450             $paddedOp .= " ";
2451         }
2452 
2453         return array("string", "", array($left, $paddedOp, $right));
2454     }
2455 
2456     /**
2457      * String concatenate
2458      *
2459      * @param   type    $left   X
2460      * @param   string  $right  X
2461      *
2462      * @return  string
2463      */
2464     protected function stringConcatenate($left, $right)
2465     {
2466         if ($strLeft = $this->coerceString($left))
2467         {
2468             if ($right[0] == "string")
2469             {
2470                 $right[1] = "";
2471             }
2472 
2473             $strLeft[2][] = $right;
2474 
2475             return $strLeft;
2476         }
2477 
2478         if ($strRight = $this->coerceString($right))
2479         {
2480             array_unshift($strRight[2], $left);
2481 
2482             return $strRight;
2483         }
2484     }
2485 
2486     /**
2487      * Make sure a color's components don't go out of bounds
2488      *
2489      * @param   type  $c  X
2490      *
2491      * @return  int
2492      */
2493     protected function fixColor($c)
2494     {
2495         foreach (range(1, 3) as $i)
2496         {
2497             if ($c[$i] < 0)
2498             {
2499                 $c[$i] = 0;
2500             }
2501 
2502             if ($c[$i] > 255)
2503             {
2504                 $c[$i] = 255;
2505             }
2506         }
2507 
2508         return $c;
2509     }
2510 
2511     /**
2512      * Op number color
2513      *
2514      * @param   type  $op   X
2515      * @param   type  $lft  X
2516      * @param   type  $rgt  X
2517      *
2518      * @return  type
2519      */
2520     protected function op_number_color($op, $lft, $rgt)
2521     {
2522         if ($op == '+' || $op == '*')
2523         {
2524             return $this->op_color_number($op, $rgt, $lft);
2525         }
2526     }
2527 
2528     /**
2529      * Op color number
2530      *
2531      * @param   type  $op   X
2532      * @param   type  $lft  X
2533      * @param   int   $rgt  X
2534      *
2535      * @return  type
2536      */
2537     protected function op_color_number($op, $lft, $rgt)
2538     {
2539         if ($rgt[0] == '%')
2540         {
2541             $rgt[1] /= 100;
2542         }
2543 
2544         return $this->op_color_color($op, $lft, array_fill(1, count($lft) - 1, $rgt[1]));
2545     }
2546 
2547     /**
2548      * Op color color
2549      *
2550      * @param   type  $op     X
2551      * @param   type  $left   X
2552      * @param   type  $right  X
2553      *
2554      * @return  type
2555      */
2556     protected function op_color_color($op, $left, $right)
2557     {
2558         $out = array('color');
2559         $max = count($left) > count($right) ? count($left) : count($right);
2560 
2561         foreach (range(1, $max - 1) as $i)
2562         {
2563             $lval = isset($left[$i]) ? $left[$i] : 0;
2564             $rval = isset($right[$i]) ? $right[$i] : 0;
2565 
2566             switch ($op)
2567             {
2568                 case '+':
2569                     $out[] = $lval + $rval;
2570                     break;
2571                 case '-':
2572                     $out[] = $lval - $rval;
2573                     break;
2574                 case '*':
2575                     $out[] = $lval * $rval;
2576                     break;
2577                 case '%':
2578                     $out[] = $lval % $rval;
2579                     break;
2580                 case '/':
2581                     if ($rval == 0)
2582                     {
2583                         $this->throwError("evaluate error: can't divide by zero");
2584                     }
2585 
2586                     $out[] = $lval / $rval;
2587                     break;
2588                 default:
2589                     $this->throwError('evaluate error: color op number failed on op ' . $op);
2590             }
2591         }
2592 
2593         return $this->fixColor($out);
2594     }
2595 
2596     /**
2597      * Lib red
2598      *
2599      * @param   type  $color  X
2600      *
2601      * @return  type
2602      */
2603     public function lib_red($color)
2604     {
2605         $color = $this->coerceColor($color);
2606 
2607         if (is_null($color))
2608         {
2609             $this->throwError('color expected for red()');
2610         }
2611 
2612         return $color[1];
2613     }
2614 
2615     /**
2616      * Lib green
2617      *
2618      * @param   type  $color  X
2619      *
2620      * @return  type
2621      */
2622     public function lib_green($color)
2623     {
2624         $color = $this->coerceColor($color);
2625 
2626         if (is_null($color))
2627         {
2628             $this->throwError('color expected for green()');
2629         }
2630 
2631         return $color[2];
2632     }
2633 
2634     /**
2635      * Lib blue
2636      *
2637      * @param   type  $color  X
2638      *
2639      * @return  type
2640      */
2641     public function lib_blue($color)
2642     {
2643         $color = $this->coerceColor($color);
2644 
2645         if (is_null($color))
2646         {
2647             $this->throwError('color expected for blue()');
2648         }
2649 
2650         return $color[3];
2651     }
2652 
2653     /**
2654      * Operator on two numbers
2655      *
2656      * @param   type  $op     X
2657      * @param   type  $left   X
2658      * @param   type  $right  X
2659      *
2660      * @return  type
2661      */
2662     protected function op_number_number($op, $left, $right)
2663     {
2664         $unit = empty($left[2]) ? $right[2] : $left[2];
2665 
2666         $value = 0;
2667 
2668         switch ($op)
2669         {
2670             case '+':
2671                 $value = $left[1] + $right[1];
2672                 break;
2673             case '*':
2674                 $value = $left[1] * $right[1];
2675                 break;
2676             case '-':
2677                 $value = $left[1] - $right[1];
2678                 break;
2679             case '%':
2680                 $value = $left[1] % $right[1];
2681                 break;
2682             case '/':
2683                 if ($right[1] == 0)
2684                 {
2685                     $this->throwError('parse error: divide by zero');
2686                 }
2687 
2688                 $value = $left[1] / $right[1];
2689                 break;
2690             case '<':
2691                 return $this->toBool($left[1] < $right[1]);
2692             case '>':
2693                 return $this->toBool($left[1] > $right[1]);
2694             case '>=':
2695                 return $this->toBool($left[1] >= $right[1]);
2696             case '=<':
2697                 return $this->toBool($left[1] <= $right[1]);
2698             default:
2699                 $this->throwError('parse error: unknown number operator: ' . $op);
2700         }
2701 
2702         return array("number", $value, $unit);
2703     }
2704 
2705     /**
2706      * Make output block
2707      *
2708      * @param   type  $type       X
2709      * @param   type  $selectors  X
2710      *
2711      * @return  stdclass
2712      */
2713     protected function makeOutputBlock($type, $selectors = null)
2714     {
2715         $b = new stdclass;
2716         $b->lines = array();
2717         $b->children = array();
2718         $b->selectors = $selectors;
2719         $b->type = $type;
2720         $b->parent = $this->scope;
2721 
2722         return $b;
2723     }
2724 
2725     /**
2726      * The state of execution
2727      *
2728      * @param   type  $block  X
2729      *
2730      * @return  stdclass
2731      */
2732     protected function pushEnv($block = null)
2733     {
2734         $e = new stdclass;
2735         $e->parent = $this->env;
2736         $e->store = array();
2737         $e->block = $block;
2738 
2739         $this->env = $e;
2740 
2741         return $e;
2742     }
2743 
2744     /**
2745      * Pop something off the stack
2746      *
2747      * @return  type
2748      */
2749     protected function popEnv()
2750     {
2751         $old = $this->env;
2752         $this->env = $this->env->parent;
2753 
2754         return $old;
2755     }
2756 
2757     /**
2758      * Set something in the current env
2759      *
2760      * @param   type  $name   X
2761      * @param   type  $value  X
2762      *
2763      * @return  void
2764      */
2765     protected function set($name, $value)
2766     {
2767         $this->env->store[$name] = $value;
2768     }
2769 
2770     /**
2771      * Get the highest occurrence entry for a name
2772      *
2773      * @param   type  $name     X
2774      * @param   type  $default  X
2775      *
2776      * @return  type
2777      */
2778     protected function get($name, $default = null)
2779     {
2780         $current = $this->env;
2781 
2782         $isArguments = $name == $this->vPrefix . 'arguments';
2783 
2784         while ($current)
2785         {
2786             if ($isArguments && isset($current->arguments))
2787             {
2788                 return array('list', ' ', $current->arguments);
2789             }
2790 
2791             if (isset($current->store[$name]))
2792             {
2793                 return $current->store[$name];
2794             }
2795             else
2796             {
2797                 $current = isset($current->storeParent) ?
2798                     $current->storeParent : $current->parent;
2799             }
2800         }
2801 
2802         return $default;
2803     }
2804 
2805     /**
2806      * Inject array of unparsed strings into environment as variables
2807      *
2808      * @param   type  $args  X
2809      *
2810      * @return  void
2811      *
2812      * @throws  Exception
2813      */
2814     protected function injectVariables($args)
2815     {
2816         $this->pushEnv();
2817         /** FOF -- BEGIN CHANGE * */
2818         $parser = new FOFLessParser($this, __METHOD__);
2819         /** FOF -- END CHANGE * */
2820         foreach ($args as $name => $strValue)
2821         {
2822             if ($name{0} != '@')
2823             {
2824                 $name = '@' . $name;
2825             }
2826 
2827             $parser->count = 0;
2828             $parser->buffer = (string) $strValue;
2829 
2830             if (!$parser->propertyValue($value))
2831             {
2832                 throw new Exception("failed to parse passed in variable $name: $strValue");
2833             }
2834 
2835             $this->set($name, $value);
2836         }
2837     }
2838 
2839     /**
2840      * Initialize any static state, can initialize parser for a file
2841      *
2842      * @param   type  $fname  X
2843      */
2844     public function __construct($fname = null)
2845     {
2846         if ($fname !== null)
2847         {
2848             // Used for deprecated parse method
2849             $this->_parseFile = $fname;
2850         }
2851     }
2852 
2853     /**
2854      * Compile
2855      *
2856      * @param   type  $string  X
2857      * @param   type  $name    X
2858      *
2859      * @return  type
2860      */
2861     public function compile($string, $name = null)
2862     {
2863         $locale = setlocale(LC_NUMERIC, 0);
2864         setlocale(LC_NUMERIC, "C");
2865 
2866         $this->parser = $this->makeParser($name);
2867         $root = $this->parser->parse($string);
2868 
2869         $this->env = null;
2870         $this->scope = null;
2871 
2872         $this->formatter = $this->newFormatter();
2873 
2874         if (!empty($this->registeredVars))
2875         {
2876             $this->injectVariables($this->registeredVars);
2877         }
2878 
2879         // Used for error messages
2880         $this->sourceParser = $this->parser;
2881         $this->compileBlock($root);
2882 
2883         ob_start();
2884         $this->formatter->block($this->scope);
2885         $out = ob_get_clean();
2886         setlocale(LC_NUMERIC, $locale);
2887 
2888         return $out;
2889     }
2890 
2891     /**
2892      * Compile file
2893      *
2894      * @param   type  $fname     X
2895      * @param   type  $outFname  X
2896      *
2897      * @return  type
2898      *
2899      * @throws  Exception
2900      */
2901     public function compileFile($fname, $outFname = null)
2902     {
2903         if (!is_readable($fname))
2904         {
2905             throw new Exception('load error: failed to find ' . $fname);
2906         }
2907 
2908         $pi = pathinfo($fname);
2909 
2910         $oldImport = $this->importDir;
2911 
2912         $this->importDir = (array) $this->importDir;
2913         $this->importDir[] = $pi['dirname'] . '/';
2914 
2915         $this->allParsedFiles = array();
2916         $this->addParsedFile($fname);
2917 
2918         $out = $this->compile(file_get_contents($fname), $fname);
2919 
2920         $this->importDir = $oldImport;
2921 
2922         if ($outFname !== null)
2923         {
2924             /** FOF - BEGIN CHANGE * */
2925             return FOFPlatform::getInstance()->getIntegrationObject('filesystem')->fileWrite($outFname, $out);
2926             /** FOF - END CHANGE * */
2927         }
2928 
2929         return $out;
2930     }
2931 
2932     /**
2933      * Compile only if changed input has changed or output doesn't exist
2934      *
2935      * @param   type  $in   X
2936      * @param   type  $out  X
2937      *
2938      * @return  boolean
2939      */
2940     public function checkedCompile($in, $out)
2941     {
2942         if (!is_file($out) || filemtime($in) > filemtime($out))
2943         {
2944             $this->compileFile($in, $out);
2945 
2946             return true;
2947         }
2948 
2949         return false;
2950     }
2951 
2952     /**
2953      * Execute lessphp on a .less file or a lessphp cache structure
2954      *
2955      * The lessphp cache structure contains information about a specific
2956      * less file having been parsed. It can be used as a hint for future
2957      * calls to determine whether or not a rebuild is required.
2958      *
2959      * The cache structure contains two important keys that may be used
2960      * externally:
2961      *
2962      * compiled: The final compiled CSS
2963      * updated: The time (in seconds) the CSS was last compiled
2964      *
2965      * The cache structure is a plain-ol' PHP associative array and can
2966      * be serialized and unserialized without a hitch.
2967      *
2968      * @param   mixed  $in     Input
2969      * @param   bool   $force  Force rebuild?
2970      *
2971      * @return  array  lessphp cache structure
2972      */
2973     public function cachedCompile($in, $force = false)
2974     {
2975         // Assume no root
2976         $root = null;
2977 
2978         if (is_string($in))
2979         {
2980             $root = $in;
2981         }
2982         elseif (is_array($in) and isset($in['root']))
2983         {
2984             if ($force or !isset($in['files']))
2985             {
2986                 /**
2987                  * If we are forcing a recompile or if for some reason the
2988                  * structure does not contain any file information we should
2989                  * specify the root to trigger a rebuild.
2990                  */
2991                 $root = $in['root'];
2992             }
2993             elseif (isset($in['files']) and is_array($in['files']))
2994             {
2995                 foreach ($in['files'] as $fname => $ftime)
2996                 {
2997                     if (!file_exists($fname) or filemtime($fname) > $ftime)
2998                     {
2999                         /**
3000                          * One of the files we knew about previously has changed
3001                          * so we should look at our incoming root again.
3002                          */
3003                         $root = $in['root'];
3004                         break;
3005                     }
3006                 }
3007             }
3008         }
3009         else
3010         {
3011             /**
3012              * TODO: Throw an exception? We got neither a string nor something
3013              * that looks like a compatible lessphp cache structure.
3014              */
3015             return null;
3016         }
3017 
3018         if ($root !== null)
3019         {
3020             // If we have a root value which means we should rebuild.
3021             $out = array();
3022             $out['root'] = $root;
3023             $out['compiled'] = $this->compileFile($root);
3024             $out['files'] = $this->allParsedFiles();
3025             $out['updated'] = time();
3026 
3027             return $out;
3028         }
3029         else
3030         {
3031             // No changes, pass back the structure
3032             // we were given initially.
3033             return $in;
3034         }
3035     }
3036 
3037     //
3038     // This is deprecated
3039     /**
3040      * Parse and compile buffer
3041      *
3042      * @param   null  $str               X
3043      * @param   type  $initialVariables  X
3044      *
3045      * @return  type
3046      *
3047      * @throws  Exception
3048      *
3049      * @deprecated  2.0
3050      */
3051     public function parse($str = null, $initialVariables = null)
3052     {
3053         if (is_array($str))
3054         {
3055             $initialVariables = $str;
3056             $str = null;
3057         }
3058 
3059         $oldVars = $this->registeredVars;
3060 
3061         if ($initialVariables !== null)
3062         {
3063             $this->setVariables($initialVariables);
3064         }
3065 
3066         if ($str == null)
3067         {
3068             if (empty($this->_parseFile))
3069             {
3070                 throw new exception("nothing to parse");
3071             }
3072 
3073             $out = $this->compileFile($this->_parseFile);
3074         }
3075         else
3076         {
3077             $out = $this->compile($str);
3078         }
3079 
3080         $this->registeredVars = $oldVars;
3081 
3082         return $out;
3083     }
3084 
3085     /**
3086      * Make parser
3087      *
3088      * @param   type  $name  X
3089      *
3090      * @return  FOFLessParser
3091      */
3092     protected function makeParser($name)
3093     {
3094         /** FOF -- BEGIN CHANGE * */
3095         $parser = new FOFLessParser($this, $name);
3096         /** FOF -- END CHANGE * */
3097         $parser->writeComments = $this->preserveComments;
3098 
3099         return $parser;
3100     }
3101 
3102     /**
3103      * Set Formatter
3104      *
3105      * @param   type  $name  X
3106      *
3107      * @return  void
3108      */
3109     public function setFormatter($name)
3110     {
3111         $this->formatterName = $name;
3112     }
3113 
3114     /**
3115      * New formatter
3116      *
3117      * @return  FOFLessFormatterLessjs
3118      */
3119     protected function newFormatter()
3120     {
3121         /** FOF -- BEGIN CHANGE * */
3122         $className = "FOFLessFormatterLessjs";
3123         /** FOF -- END CHANGE * */
3124         if (!empty($this->formatterName))
3125         {
3126             if (!is_string($this->formatterName))
3127                 return $this->formatterName;
3128             /** FOF -- BEGIN CHANGE * */
3129             $className = "FOFLessFormatter" . ucfirst($this->formatterName);
3130             /** FOF -- END CHANGE * */
3131         }
3132 
3133         return new $className;
3134     }
3135 
3136     /**
3137      * Set preserve comments
3138      *
3139      * @param   type  $preserve  X
3140      *
3141      * @return  void
3142      */
3143     public function setPreserveComments($preserve)
3144     {
3145         $this->preserveComments = $preserve;
3146     }
3147 
3148     /**
3149      * Register function
3150      *
3151      * @param   type  $name  X
3152      * @param   type  $func  X
3153      *
3154      * @return  void
3155      */
3156     public function registerFunction($name, $func)
3157     {
3158         $this->libFunctions[$name] = $func;
3159     }
3160 
3161     /**
3162      * Unregister function
3163      *
3164      * @param   type  $name  X
3165      *
3166      * @return  void
3167      */
3168     public function unregisterFunction($name)
3169     {
3170         unset($this->libFunctions[$name]);
3171     }
3172 
3173     /**
3174      * Set variables
3175      *
3176      * @param   type  $variables  X
3177      *
3178      * @return  void
3179      */
3180     public function setVariables($variables)
3181     {
3182         $this->registeredVars = array_merge($this->registeredVars, $variables);
3183     }
3184 
3185     /**
3186      * Unset variable
3187      *
3188      * @param   type  $name  X
3189      *
3190      * @return  void
3191      */
3192     public function unsetVariable($name)
3193     {
3194         unset($this->registeredVars[$name]);
3195     }
3196 
3197     /**
3198      * Set import dir
3199      *
3200      * @param   type  $dirs  X
3201      *
3202      * @return  void
3203      */
3204     public function setImportDir($dirs)
3205     {
3206         $this->importDir = (array) $dirs;
3207     }
3208 
3209     /**
3210      * Add import dir
3211      *
3212      * @param   type  $dir  X
3213      *
3214      * @return  void
3215      */
3216     public function addImportDir($dir)
3217     {
3218         $this->importDir = (array) $this->importDir;
3219         $this->importDir[] = $dir;
3220     }
3221 
3222     /**
3223      * All parsed files
3224      *
3225      * @return  type
3226      */
3227     public function allParsedFiles()
3228     {
3229         return $this->allParsedFiles;
3230     }
3231 
3232     /**
3233      * Add parsed file
3234      *
3235      * @param   type  $file  X
3236      *
3237      * @return  void
3238      */
3239     protected function addParsedFile($file)
3240     {
3241         $this->allParsedFiles[realpath($file)] = filemtime($file);
3242     }
3243 
3244     /**
3245      * Uses the current value of $this->count to show line and line number
3246      *
3247      * @param   type  $msg  X
3248      *
3249      * @return  void
3250      */
3251     protected function throwError($msg = null)
3252     {
3253         if ($this->sourceLoc >= 0)
3254         {
3255             $this->sourceParser->throwError($msg, $this->sourceLoc);
3256         }
3257 
3258         throw new exception($msg);
3259     }
3260 
3261     /**
3262      * Compile file $in to file $out if $in is newer than $out
3263      * Returns true when it compiles, false otherwise
3264      *
3265      * @param   type  $in    X
3266      * @param   type  $out   X
3267      * @param   self  $less  X
3268      *
3269      * @return  type
3270      */
3271     public static function ccompile($in, $out, $less = null)
3272     {
3273         if ($less === null)
3274         {
3275             $less = new self;
3276         }
3277 
3278         return $less->checkedCompile($in, $out);
3279     }
3280 
3281     /**
3282      * Compile execute
3283      *
3284      * @param   type  $in     X
3285      * @param   type  $force  X
3286      * @param   self  $less   X
3287      *
3288      * @return  type
3289      */
3290     public static function cexecute($in, $force = false, $less = null)
3291     {
3292         if ($less === null)
3293         {
3294             $less = new self;
3295         }
3296 
3297         return $less->cachedCompile($in, $force);
3298     }
3299 
3300     protected static $cssColors = array(
3301         'aliceblue'              => '240,248,255',
3302         'antiquewhite'           => '250,235,215',
3303         'aqua'                   => '0,255,255',
3304         'aquamarine'             => '127,255,212',
3305         'azure'                  => '240,255,255',
3306         'beige'                  => '245,245,220',
3307         'bisque'                 => '255,228,196',
3308         'black'                  => '0,0,0',
3309         'blanchedalmond'         => '255,235,205',
3310         'blue'                   => '0,0,255',
3311         'blueviolet'             => '138,43,226',
3312         'brown'                  => '165,42,42',
3313         'burlywood'              => '222,184,135',
3314         'cadetblue'              => '95,158,160',
3315         'chartreuse'             => '127,255,0',
3316         'chocolate'              => '210,105,30',
3317         'coral'                  => '255,127,80',
3318         'cornflowerblue'         => '100,149,237',
3319         'cornsilk'               => '255,248,220',
3320         'crimson'                => '220,20,60',
3321         'cyan'                   => '0,255,255',
3322         'darkblue'               => '0,0,139',
3323         'darkcyan'               => '0,139,139',
3324         'darkgoldenrod'          => '184,134,11',
3325         'darkgray'               => '169,169,169',
3326         'darkgreen'              => '0,100,0',
3327         'darkgrey'               => '169,169,169',
3328         'darkkhaki'              => '189,183,107',
3329         'darkmagenta'            => '139,0,139',
3330         'darkolivegreen'         => '85,107,47',
3331         'darkorange'             => '255,140,0',
3332         'darkorchid'             => '153,50,204',
3333         'darkred'                => '139,0,0',
3334         'darksalmon'             => '233,150,122',
3335         'darkseagreen'           => '143,188,143',
3336         'darkslateblue'          => '72,61,139',
3337         'darkslategray'          => '47,79,79',
3338         'darkslategrey'          => '47,79,79',
3339         'darkturquoise'          => '0,206,209',
3340         'darkviolet'             => '148,0,211',
3341         'deeppink'               => '255,20,147',
3342         'deepskyblue'            => '0,191,255',
3343         'dimgray'                => '105,105,105',
3344         'dimgrey'                => '105,105,105',
3345         'dodgerblue'             => '30,144,255',
3346         'firebrick'              => '178,34,34',
3347         'floralwhite'            => '255,250,240',
3348         'forestgreen'            => '34,139,34',
3349         'fuchsia'                => '255,0,255',
3350         'gainsboro'              => '220,220,220',
3351         'ghostwhite'             => '248,248,255',
3352         'gold'                   => '255,215,0',
3353         'goldenrod'              => '218,165,32',
3354         'gray'                   => '128,128,128',
3355         'green'                  => '0,128,0',
3356         'greenyellow'            => '173,255,47',
3357         'grey'                   => '128,128,128',
3358         'honeydew'               => '240,255,240',
3359         'hotpink'                => '255,105,180',
3360         'indianred'              => '205,92,92',
3361         'indigo'                 => '75,0,130',
3362         'ivory'                  => '255,255,240',
3363         'khaki'                  => '240,230,140',
3364         'lavender'               => '230,230,250',
3365         'lavenderblush'          => '255,240,245',
3366         'lawngreen'              => '124,252,0',
3367         'lemonchiffon'           => '255,250,205',
3368         'lightblue'              => '173,216,230',
3369         'lightcoral'             => '240,128,128',
3370         'lightcyan'              => '224,255,255',
3371         'lightgoldenrodyellow'   => '250,250,210',
3372         'lightgray'              => '211,211,211',
3373         'lightgreen'             => '144,238,144',
3374         'lightgrey'              => '211,211,211',
3375         'lightpink'              => '255,182,193',
3376         'lightsalmon'            => '255,160,122',
3377         'lightseagreen'          => '32,178,170',
3378         'lightskyblue'           => '135,206,250',
3379         'lightslategray'         => '119,136,153',
3380         'lightslategrey'         => '119,136,153',
3381         'lightsteelblue'         => '176,196,222',
3382         'lightyellow'            => '255,255,224',
3383         'lime'                   => '0,255,0',
3384         'limegreen'              => '50,205,50',
3385         'linen'                  => '250,240,230',
3386         'magenta'                => '255,0,255',
3387         'maroon'                 => '128,0,0',
3388         'mediumaquamarine'       => '102,205,170',
3389         'mediumblue'             => '0,0,205',
3390         'mediumorchid'           => '186,85,211',
3391         'mediumpurple'           => '147,112,219',
3392         'mediumseagreen'         => '60,179,113',
3393         'mediumslateblue'        => '123,104,238',
3394         'mediumspringgreen'      => '0,250,154',
3395         'mediumturquoise'        => '72,209,204',
3396         'mediumvioletred'        => '199,21,133',
3397         'midnightblue'           => '25,25,112',
3398         'mintcream'              => '245,255,250',
3399         'mistyrose'              => '255,228,225',
3400         'moccasin'               => '255,228,181',
3401         'navajowhite'            => '255,222,173',
3402         'navy'                   => '0,0,128',
3403         'oldlace'                => '253,245,230',
3404         'olive'                  => '128,128,0',
3405         'olivedrab'              => '107,142,35',
3406         'orange'                 => '255,165,0',
3407         'orangered'              => '255,69,0',
3408         'orchid'                 => '218,112,214',
3409         'palegoldenrod'          => '238,232,170',
3410         'palegreen'              => '152,251,152',
3411         'paleturquoise'          => '175,238,238',
3412         'palevioletred'          => '219,112,147',
3413         'papayawhip'             => '255,239,213',
3414         'peachpuff'              => '255,218,185',
3415         'peru'                   => '205,133,63',
3416         'pink'                   => '255,192,203',
3417         'plum'                   => '221,160,221',
3418         'powderblue'             => '176,224,230',
3419         'purple'                 => '128,0,128',
3420         'red'                    => '255,0,0',
3421         'rosybrown'              => '188,143,143',
3422         'royalblue'              => '65,105,225',
3423         'saddlebrown'            => '139,69,19',
3424         'salmon'                 => '250,128,114',
3425         'sandybrown'             => '244,164,96',
3426         'seagreen'               => '46,139,87',
3427         'seashell'               => '255,245,238',
3428         'sienna'                 => '160,82,45',
3429         'silver'                 => '192,192,192',
3430         'skyblue'                => '135,206,235',
3431         'slateblue'              => '106,90,205',
3432         'slategray'              => '112,128,144',
3433         'slategrey'              => '112,128,144',
3434         'snow'                   => '255,250,250',
3435         'springgreen'            => '0,255,127',
3436         'steelblue'              => '70,130,180',
3437         'tan'                    => '210,180,140',
3438         'teal'                   => '0,128,128',
3439         'thistle'                => '216,191,216',
3440         'tomato'                 => '255,99,71',
3441         'transparent'            => '0,0,0,0',
3442         'turquoise'              => '64,224,208',
3443         'violet'                 => '238,130,238',
3444         'wheat'                  => '245,222,179',
3445         'white'                  => '255,255,255',
3446         'whitesmoke'             => '245,245,245',
3447         'yellow'                 => '255,255,0',
3448         'yellowgreen'            => '154,205,50'
3449     );
3450 }
3451 
Joomla! Framework TM API documentation generated by ApiGen 2.8.0
Joomla!® and Joomla! Framework™ are trademarks of Open Source Matters, Inc. in the United States and other countries.