Přehled novinek a změn ve verzi 2
- David Grudl
- Nette Core | 8218
Do finální verze 2.0 vás čeká velká řada významných novinek. Tady je přehled toho, co už v repozitáři najdete. Seznam budu postupně aktualizovat. Viz také roadmap.
Aby tu byl trošku pořádek, poprosím diskutující, aby na samostatná témata jako jsou feature requesty, bug reporty, podpora XML, apod zakládali samostatné témata.
Application
- vylepšená adresářová struktura
- do šablon se automaticky předává User v proměnné
$template->user
(pokud proměnnou používáte jinak, nevadí, prostě ji přepíšete). - pokud nepoužíváte vlastní ErrorPresenter, zobrazí výchozí srozumitelné chybové hlášky pro HTTP chyby 4xx, 403, 404, 405, 410 and 500
- do Error presenteru se nyní přenáší persistentní parametry
- v masce Route lze uvádět výchozí hodnoty
new Route('<presenter=Homepage><action=default>')
- druhý parameter Route může být řetězec ve tvaru
Presenter:action
, viz jednodušší routování - lze vytvářet MultiRouter pro konkrétní modul (specifikovaný v konstruktoru)
- konfigurace INI nahrazeny za Neon, obdoba YAML
- DownloadResponse podporuje navazování pro velké soubory (thx Ondrej Mirtes)
- a pozor BC break:
- změna rozhraní
IRouter
, druhý parametr methodyconstructUrl()
je nyní objektNette\Http\Url
. - proměnná
$baseUri
v šabloně odpovídá$basePath
doplněné o protokol a doménu. - IPresenterLoader nahrazen za IPresenterFactory
IPresenterResponse::send()
přijímá parametryNette\Http\IRequest
aIResponse
)
- změna rozhraní
Šablony
- chybné makra v šabloně se vizualizují v Laděnce, zobrazí se šablona s označeným řádku
- syntax všech maker byla sjednocena a rozšířena: o zjednodušený zápis
podmínek
{=$var ? item}
a polí{=[a, b, c]|join:' '}
- nová makra
{first}, {last} a {sep}
usnadňující iterace a{l} a {r}
pro zápis levé nebo pravé složené závorky - vylepšení doznala makra
{cache} … {/cache}, včetně podmíněného kešování
via
{cache if => ...}
- vylepšena byla makra
{var ...} a {default ...}
, je možné používat intuitivnější zápis{var $prom = 123, $name = ahoj}
. - nová atributová makra
n:class
an:href
a univerzálnín:attr-xxx="..."
příklad:<li n:class="item, $iterator->odd ? odd : even, $selected ? selected">
- dokonce lze použít i komentář
{var $prom = 123 /*, $name = ahoj*/}
- rozvinutí proměnné pole
{link default $id, (expand) $args, lang => cs}
- obecně je preferovaný zápis
{control ...}
před{widget ...}
a{var ...}
před{assign ...}
- deprecated jsou makra
{attr}, {assign}, {widget}
- pro soubory se šablonami je preferovaná přípona
.latte
- existenci bloku lze testovat makrem
{ifset #block}
- a pozor BC break:
- v Nette\Templating se přejmenovala třída Template → FileTemplate a BaseTemplate → Template
- šablony musí být v UTF-8
- makra se nyní nesmí křížit
Nette\Database
- zcela nová vrstva pro práci s databází (dokumentace)
Nette\Diagnostics – ano, i tak dokonalé stvoření jako je Laděnka lze ještě vylepšovat :-)
- stránka „bluescreen“ doznala vizuálního faceliftu
- chytřejším způsobem rozhoduje, který zdrojový kód z debug-trace bude vykreslen rozbalený, případně který se přeskočí
- pomocí
Nette\Diagnostics\Debugger::$scream = TRUE
lze potlačit potláčení chybových zpráv operátorem shut-up (@) - v případě fatální chyby v produkčním režimu místo prázdné obrazovky ukáže univerzální srozumitelnou chybovou hlášku
- u všech zalogovaných chyb uvádí URL, na kterém k chybě došlo
- přidána metoda
Debug::log($message [, $priority])
, která slouží k zalogování textové zprávy nebo výjimky. Pokud je jako druhý parametr uvedenDebug::ERROR
, bude informace o chybě odeslána také emailem (samozřejmě jen jednou) - zároveň je deprecated původní Debug::processException(), takže ji
nahraďte za
Debug::log($exception, Debug::ERROR)
- kliknutím na jméno souboru jej otevřete ve vašem editoru
- Debug lze nyní konfigurovat pomocí statických proměnných, tedy nejen
jednorázově při volání metody
enable()
- jde konkrétně o proměnnou
Debug::$email
, jejíž nastavení aktivuje odesílání emailů - dále o proměnnou
Debug::$logDirectory
, která určuje adresář, kam se bude logovat. Jejím nastavením se logování aktivuje. Pokud se adresář neurčí a jsme v produkčním režimu, detekuje se automaticky podle aktualizované adresářové struktury. - POZOR: nyní se tedy neurčuje soubor s logem, ale
adresář s logy. Pokud používáte druhý parametr metody
enable()
, upravte si jej. - detekce vývojářského/produkčního prostředí funguje s proxy servery
- příjemná vychytávka: „bluescreen“ se nesnaží zahazovat výstup v output bufferu, naopak vše vypíše a vykreslí se přes něj. Skrývat a zobrazovat jej můžete stiskem klávesy ESC. Silně návykové :-)
- podpora FirePHP byla nahrazena za FireLogger (pozor, vyžaduje FireLogger 0.9) (viz také otevírání souborů z FireLoggeru ve vašem editoru)
- …a samozřejmě ve verzi 2 je Debug Bar
Formuláře Nette\Forms:
- InstantClientScript
nahrazen za Unobtrusive JavaScript (stále ve vývoji, validování
vyžaduje načíst skript via
<script src=".../netteForms.js"></script>
) - přidána podpora pro HTML5 (tyto změny nejsou konečné)
- přidán validátor Form::IMAGE pro jpg/png/gif soubory a validátor Form::PATTERN
- vylepšená validace Form::URL
- odstraněna podpora jiných než UTF-8 kódování
- a možný BC break: getValues() vrací místo pole objekt ArrayHash (chová se jako pole)
Cache
- Nette\Caching: tagy a priority nejsou natvrdo ukládány do SQLite databáze, ale o úložiště se stará libovolný ICacheJournal (thx Panda). V tuto chvíli se testuje FileJournal, který nevyžaduje žádné databázové rozšíření (thx Jakub Kulhan a Jakub „acci“ Onderka)
- klíče používané v cache už nemusí být jen (krátké) řetězce, ale cokoliv, například pole
- přidán Nette\Caching\Storages\MemoryStorage udržující data v paměti po dobu požadavku
- nová metoda
Cache::call()
pro snadné kešování výsledků funkcí
Další
- nové třídy Nette\Utils\Finder a SmtpMailer
- String: přidány metody length(), compare(), toAscii(), random(), firstUpper()
- pro bezpečné
regulární výrazy přidány metody
String::split(), String::match(), String::matchAll()
,String::replace(), ArrayTools::grep()
- ze stejného důvodu přidána třída
Nette\Utils\Json
s metodamyencode() a decode()
- Nette\Utils\Html podporuje datové atributy a má novou funkci addAttributes()
- nová fce Nette\Utils\MimeTypeDetector::fromFile($file) zjišťuje mime type
souboru a fromString($s); nicméně v PHP 5.3 používejte
finfo_file(finfo_open(FILEINFO_MIME_TYPE), $file);
(platí i pro 0.9) - Image::rotate(…) rotuje přímo aktuální obrázek namísto toho, aby rotovaný vracelo
- Image defaultně úkládá soubory s průhledností
- RobotLoader podporuje v netterobots.txt podadresáře (thx Panda) a detekuje přesunuté soubory (thx Jan Tvrdík)
- RobotLoader mnohem inteligentněji pracuje s cache, téměř by nemělo být potřeba cache mazat
- rozhraní IAuthenticator dostává v parametru
$credentials
pole všech parametrů, tak jak je předáte metoděUser::login(...)
. Pozor! jméno a heslo je tak pod klíčy 0 a 1. Pokud používáte konstantyIAuthenticator::USERNAME
aPASSWORD
, netřeba nic v kódu upravovat. Permission
: interfaceIPermissionAssertion
nahrazen callbackem- loader.php defineje konstanty
NETTE, NETTE_VERSION_ID & NETTE_PACKAGE, NETTE_DIR
(platí i pro 0.9) - loader.php také resetuje direktivy
error_reporting
(na E_ALL + E_STRICT),iconv.internal_encoding, mbstring.internal_encoding
na UTF-8 - Nette\Tests zcela přepracován, odstraněny dumpy() a používají se jen asserce (platí i pro 0.9)
- přejmenováno a přepsán Nette\IO\SafeStream → Nette\Utils\SafeStream a registruje se automaticky
- díky novému generátoru API dokumentace je konečně plnohodnotná dokumentace pro PHP 5.3 verzi. Nyní ji najdete přímo v distribučním archívu.
- vizuálním faceliftem prošly příklady v examples, Laděnka, skeleton i Requirement Checker
- Nette\Http\Session vyžaduje pro konfiguraci přítomnost funkce
ini_set
. Pokud funkce není k dispozici, vyhodí výjimku. Dá se tomu předejít nastavením proměnnéNette\Framework::$iAmUsingBadHost = TRUE
. - Nette\Object podporuje write-only properties
- změna licence na BSD, GPL2, GPL3
- a pozor BC break:
- třída ImageMagick přesunuta do doplňků
Depencency injection:
- Application je nezávislá na Environment
- Nette\Caching je nezávislé na Environment
- RobotLoader je nezávislý na Environment
- globální RobotLoader je dostupný přes
Environemnt::getRobotLoader()
- Nette\ServiceLocator byl nakonec přejmenován na Nette\DI\Context
- Nette\Http\Request je nezávislá na superglobálních proměnných; akutální HttpRequest generuje továrnička RequestFactory
- Environment::getVariable() při dotazu na nedefinovanou proměnnou vyhodí výjimku, pokud tedy druhým parametrem nedefinujeme výchozí hodnotu
- aby bylo Nette méně magické, zmizelo i těch pár zbývajících předdefinovaných proměnných prostředí: encoding, lang, cacheBase, tempDir, logDir. Jak se poslední dvě nastavují viz příspěvek o nové adresářové struktuře
Distribuce na stránce download:
- verze 0.9 stable je ověřená, ale už nevyvíjená. Nový projekt bych na ní spíše nezakládal, protože přechod na verzi 2 bude nejsložitější.
- verze 2.0 alpha by měla být plně funkční a použitelná na ostrém prostředí, označení „alpha“ zde znamená, že do vydání finální verze se některé vlastnosti ještě změní (třeba i zásadně). Přechod však bude snadnější než z verze 0.9, nový projekt bych proto doporučil zakládat na ní.
- verze 2.0 dev je snapshotem repozitáře, obsahuje všechny novinky, ale i všechny aktuálně rozpracované věci. Použití doporučuji pouze zkušeným Nettistům. Jejím používám pomáhají testovat a vyvíjet framework.
- vrana
- Člen | 131
Inspirován Xdebugem a Symfony frameworkem jsem do Nette\Debug
přidal možnost při výpisu chyby vytvořit odkaz, který v editoru otevře
soubor, ve kterém došlo k chybě. Povolení této možnosti na straně Nette
je jednoduché:
<?php
Nette\Debug::$editorLink = "editor:%filename:%line";
?>
Ve Firefoxu je protokol potřeba povolit pomocí
network.protocol-handler.expose.editor
nebo
network.protocol-handler.expose-all
v about:config
,
defaultně by to ale mělo být zapnuté. Ve Windows je potřeba protokol
zaregistrovat v registrech:
REGEDIT4
[HKEY_CLASSES_ROOT\editor]
@="URL:editor Protocol"
"URL Protocol"=""
[HKEY_CLASSES_ROOT\editor\shell\open\command]
@="\"C:\\Program Files\\PHP\\php.exe\" \"C:\\Program Files\\PHP\\editor.php\" \"%1\""
A soubor editor.php
může vypadat třeba takhle:
<?php
list(, $drive, $filename, $line) = explode(":", $_SERVER["argv"][1]);
$cmd = "C:\\Progra~1\\SciTE\\scite.exe \"-open:$drive:" . addslashes(urldecode($filename)) . "\" -goto:$line";
shell_exec($cmd);
?>
Místo protokolu editor
lze zaregistrovat i jakýkoliv jiný
protokol, API se ještě může změnit a taky nejspíš změní – pokud si
dobře pamatuji, tak %filename
David přejmenuje na
%file
, $editorLink
na $editor
a možná
ještě něco dalšího. Také přislíbil doplnit tuto funkci do souborů
zobrazovaných ve stack trace.
Editoval vrana (25. 9. 2010 23:20)
- David Grudl
- Nette Core | 8218
Šablony v Latte musí být zapsány v UTF-8 a makra se nesmí křížit. Pokud k tomu dojde, budete upozorněni výjimkou (a jistě oceníte, že součástí Laděnky je i výpis šablony s označením odpovídajícího řádku).
Zároveň je také nutné uzavírat makra stejnou značkou,
jakou byly otevřeny. Mohlo by to způsobit komplikaci v případě dvojice
např. {ifCurrent}
nebo {ifset}...{/if}
, kterou je
třeba nahradit za {ifset}...{/ifset}
.
Pro kontrolu šablon můžete využít nástroj Code Checker dodávaný v distribuci.
- crempa
- Člen | 198
Tak jo zase budu za otravnyho rejpala, ale existuje nejaka predstava o oprave nahlasenych bugu predevsim v sekci ajaxu? Konkretne pak treba dynamicke snippety, include vs snippet nebo problem s predavanim parametru komponentam a renderem?
Cert vem dokumentaci, nove formulare a database vrstvu… to jsou fajn veci ktere fw potrebuje, ale kdyz nejde to co slo v 0.9 tak se pak tezko switchuje a nebo realizuje neco komplexnejsiho..
btw: co takhle stanovit donation za kterou se dane chyby vyresi, jsem pripraven prispet :)
- David Grudl
- Nette Core | 8218
Upozorňuji na možné BC breaky z posledních týdnů:
- Form::getValues() nevrací klasické pole, ale objekt ArrayHash, který se
jako pole umí chovat. Pokud potřebujete výsledek přetypovat na pole, lze
použít klasické
(array) $values
přetypování. Tahle úprava může být zrádná, doporučuji vyhledat v kódu getValues() a zkontrolovat, jak se s výsledkem nakládá, nebo rovnou upravit$form->getValues()
za(array) $form->getValues()
- IPresenterLoader nahrazen za IPresenterFactory s upraveným rozhraním pro potřeby dependency injection
- rozhraní IPresenterResponse::send() nyní očekává dva parametry, Nette\Web\IHttpRequest a IHttpResponse
- Nette\Image standardně ukládá obrázky s průhledností
- třída Nette\ImageMagick byla přesunuta do doplňků, proměnná Image::$useImageMagick odstraněna
- Patrik Votoček
- Člen | 2221
David Grudl napsal(a):
- Form::getValues() nevrací klasické pole, ale objekt ArrayHash, který se jako pole umí chovat. Pokud potřebujete výsledek přetypovat na pole, lze použít klasické
(array) $values
přetypování. Tahle úprava může být zrádná, doporučuji vyhledat v kódu getValues() a zkontrolovat, jak se s výsledkem nakládá, nebo rovnou upravit$form->getValues()
za(array) $form->getValues()
Jakej to má vlastně důvod/smysl/určení? (nevadí mě to jen bych to rád věděl)
Edit: nestálo by za to nahradit ArrayHash
em i
Nette\Config\Config
?
Editoval Patrik Votoček (1. 3. 2011 16:31)
- Honza Marek
- Člen | 1664
Patrik Votoček napsal(a):
$values->item
je o dva znaky kratší než
$values['item']
. Tož to je fajné, ni?
Editoval Honza Marek (1. 3. 2011 16:36)
- o5
- Člen | 416
Patrik Votoček napsal(a):
protože má
$form['item']->value;
To je argument jako prase teda. Nechybi mi tam tedy tolik $form->getValue(‚item‘), ale mozna to zas takova blbost neni. Jako je treba $this->getParam(‚key‘), kterej pokud ‚key‘ neexistuje, vraci NULL (nebo to co je jako $default), misto osetrovani pomoci isset apod. by tohle nakonec nebylo tak bezvyznamny.
- Filip Procházka
- Moderator | 4668
Ale hloupost. Jak to pracuješ s formuláři, že potřebuješ ošetřovat issetem prvky? A proč si to nenapíšeš?
Nette\Forms\FormContainer::extensionMethod()
Nette\Forms\FormControl::extensionMethod()
;)
Editoval HosipLan (2. 3. 2011 11:39)
- mcmatak
- Člen | 504
pěkně jsem si teď dal, když jsem několik hodin strávil nad tím proč
najednou app, která vždy fungovala, nejede, protože Identity najednou má
property public $id, takže dříve používané
getUser()->getIdentity()->id už nefunguje, protože nešahá do
identity->data, ale logicky do své property, ve které ovšem dříve byl
username, tudíž všechny vlastní Authenticatory nastavují
Identity takto
Identity($data[‚user‘], $roles, $data)
jenomže v nette > 0.9 je nastavení jiné
Identity($data[‚id‘], $roles, $data)
v changelog ani zmínka, je šance že někdy bude existovat changelog na přechod mezi 0.9 a 2.0 ?
ale asi zbytečná otázka co
- Honza Marek
- Člen | 1664
On ten changelog asi nikdo neumí napsat. Každý zná buď 0.9 nebo 2.0, podle toho co používá.
- David Grudl
- Nette Core | 8218
Nové jmenné prostory
Přehled všech tříd se změněným názvem:
- bez prostoru
InvalidStateException
→Nette\InvalidStateException
NotImplementedException
→Nette\NotImplementedException
NotSupportedException
→Nette\NotSupportedException
DeprecatedException
→Nette\DeprecatedException
MemberAccessException
→Nette\MemberAccessException
FatalErrorException
→Nette\FatalErrorException
- ArgumentOutOfRangeException (zrušeno)
- Nette
IComponent
→Nette\ComponentModel\IComponent
Component
→Nette\ComponentModel\Component
IComponentContainer
→Nette\ComponentModel\IContainer
ComponentContainer
→Nette\ComponentModel\Container
AmbiguousServiceException
→Nette\DI\AmbiguousServiceException
IContext
→Nette\DI\IContext
Context
→Nette\DI\Context
Configurator
→Nette\DI\Configurator
Debug
→Nette\Diagnostics\Debugger
DebugPanel
→Nette\Diagnostics\Panel
IDebugPanel
→Nette\Diagnostics\IPanel
DebugHelpers
→Nette\Diagnostics\Helpers
ITranslator
→Nette\Localization\ITranslator
SafeStream
→Nette\Utils\SafeStream
Finder
→Nette\Utils\Finder
ArrayTools
→Nette\Utils\Arrays
Json
→Nette\Utils\Json
Neon
→Nette\Utils\Neon
Paginator
→Nette\Utils\Paginator
String
→Nette\Utils\Strings
Tools
→ rozděleno do třídNette\DateTime
Nette\Utils\CriticalSection
Nette\Utils\MimeTypeDetector
CallbackFilterIterator
→Nette\Iterators\Filter
GenericRecursiveIterator
→Nette\Iterators\Recursor
InstanceFilterIterator
→Nette\Iterators\InstanceFilter
MapIterator
→Nette\Iterators\Mapper
RecursiveCallbackFilterIterator
→Nette\Iterators\RecursiveFilter
SmartCachingIterator
→Nette\Iterators\CachingIterator
- Nette\Application
PresenterRequest
→Nette\Application\Request
IPresenterResponse
→Nette\Application\IResponse
DownloadResponse
→Nette\Application\Responses\FileResponse
ForwardingResponse
→Nette\Application\Responses\ForwardResponse
JsonResponse
→Nette\Application\Responses\JsonResponse
RedirectingResponse
→Nette\Application\Responses\RedirectResponse
RenderResponse
→Nette\Application\Responses\TextResponse
CliRouter
→Nette\Application\Routers\CliRouter
MultiRouter
→Nette\Application\Routers\RouteList
Route
→Nette\Application\Routers\Route
SimpleRouter
→Nette\Application\Routers\SimpleRouter
RoutingDebugger
→Nette\Application\Diagnostics\RoutingPanel
Link
→Nette\Application\UI\Link
IRenderable
→Nette\Application\UI\IRenderable
ISignalReceiver
→Nette\Application\UI\ISignalReceiver
IStatePersistent
→Nette\Application\UI\IStatePersistent
IPartiallyRenderable
→Nette\Application\UI\IPartiallyRenderable
Presenter
→Nette\Application\UI\Presenter
PresenterComponent
→Nette\Application\UI\PresenterComponent
PresenterComponentReflection
→Nette\Application\UI\PresenterComponentReflection
Control
→Nette\Application\UI\Control
AppForm
→Nette\Application\UI\Form
BadSignalException
→Nette\Application\UI\BadSignalException
InvalidLinkException
→Nette\Application\UI\InvalidLinkException
- Nette\Forms
Button
→Nette\Forms\Controls\Button
Checkbox
→Nette\Forms\Controls\Checkbox
FileUpload
→Nette\Forms\Controls\UploadControl
FormControl
→Nette\Forms\Controls\BaseControl
HiddenField
→Nette\Forms\Controls\HiddenField
ImageButton
→Nette\Forms\Controls\ImageButton
MultiSelectBox
→Nette\Forms\Controls\MultiSelectBox
RadioList
→Nette\Forms\Controls\RadioList
SelectBox
→Nette\Forms\Controls\SelectBox
SubmitButton
→Nette\Forms\Controls\SubmitButton
TextArea
→Nette\Forms\Controls\TextArea
TextBase
→Nette\Forms\Controls\TextBase
TextInput
→Nette\Forms\Controls\TextInput
FormGroup
→Nette\Forms\ControlGroup
FormContainer
→Nette\Forms\Container
IFormControl
→Nette\Forms\IControl
DefaultFormRenderer
→Nette\Forms\Rendering\DefaultFormRenderer
- Nette\Caching
ICacheStorage
→Nette\Caching\IStorage
DummyStorage
→Nette\Caching\Storages\DevNullStorage
FileJournal
→Nette\Caching\Storages\FileJournal
FileStorage
→Nette\Caching\Storages\FileStorage
ICacheJournal
→Nette\Caching\Storages\IJournal
MemcachedStorage
→Nette\Caching\Storages\MemcachedStorage
MemoryStorage
→Nette\Caching\Storages\MemoryStorage
- Nette\Config
ConfigAdapterIni
→Nette\Config\IniAdapter
ConfigAdapterNeon
→Nette\Config\NeonAdapter
IConfigAdapter
→Nette\Config\IAdapter
- Nette\Database\Selector
GroupedTableSelection
→Nette\Database\Table\GroupedSelection
TableRow
→Nette\Database\Table\ActiveRow
TableSelection
→Nette\Database\Table\Selection
- Nette\Loaders
LimitedScope
→Nette\Utils\LimitedScope
- Nette\Mail
Mail
→Nette\Mail\Message
MailMimePart
→Nette\Mail\MimePart
- Nette\Reflection
ClassReflection
→Nette\Reflection\ClassType
ExtensionReflection
→Nette\Reflection\Extension
FunctionReflection
→Nette\Reflection\GlobalFunction
MethodReflection
→Nette\Reflection\Method
ParameterReflection
→Nette\Reflection\Parameter
PropertyReflection
→Nette\Reflection\Property
- Nette\Templates
LatteFilter
→Nette\Latte\Engine
LatteMacros
→Nette\Latte\DefaultMacros
LatteException
→Nette\Latte\ParseException
CachingHelper
→Nette\Caching\OutputHelper
TemplateException
→Nette\Templating\FilterException
TemplateCachestorage
→Nette\Templating\PhpFileStorage
TemplateHelpers
→Nette\Templating\DefaultHelpers
TemplateFilters
→ přesunuto do doplňků
- Nette\Web
Html
→Nette\Utils\Html
HttpContext
→Nette\Http\Context
IHttpRequest
→Nette\Http\IRequest
HttpRequest
→Nette\Http\Request
IHttpResponse
→Nette\Http\IResponse
HttpResponse
→Nette\Http\Response
HttpRequestFactory
→Nette\Http\RequestFactory
HttpUploadedFile
→Nette\Http\FileUpload
ISessionStorage
→Nette\Http\ISessionStorage
Session
→Nette\Http\Session
SessionNamespace
→Nette\Http\SessionNamespace
Uri
→Nette\Http\Url
UriScript
→Nette\Http\UrlScript
IUser
→Nette\Http\IUser
User
→Nette\Http\User
- Patrik Votoček
- Člen | 2221
Koukám že už je určen datum vydání 2.0 Beta… bude se aktualizovat Roadmap ?