Creative Commons Legal Code CC0 1.0 Universal CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER. Statement of Purpose The laws of most jurisdictions throughout the world automatically confer exclusive Copyright and Related Rights (defined below) upon the creator and subsequent owner(s) (each and all, an "owner") of an original work of authorship and/or a database (each, a "Work"). Certain owners wish to permanently relinquish those rights to a Work for the purpose of contributing to a commons of creative, cultural and scientific works ("Commons") that the public can reliably and without fear of later claims of infringement build upon, modify, incorporate in other works, reuse and redistribute as freely as possible in any form whatsoever and for any purposes, including without limitation commercial purposes. These owners may contribute to the Commons to promote the ideal of a free culture and the further production of creative, cultural and scientific works, or to gain reputation or greater distribution for their Work in part through the use and efforts of others. For these and/or other purposes and motivations, and without any expectation of additional consideration or compensation, the person associating CC0 with a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly distribute the Work under its terms, with knowledge of his or her Copyright and Related Rights in the Work and the meaning and intended legal effect of CC0 on those rights. 1. Copyright and Related Rights. A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following: i. the right to reproduce, adapt, distribute, perform, display, communicate, and translate a Work; ii. moral rights retained by the original author(s) and/or performer(s); iii. publicity and privacy rights pertaining to a person's image or likeness depicted in a Work; iv. rights protecting against unfair competition in regards to a Work, subject to the limitations in paragraph 4(a), below; v. rights protecting the extraction, dissemination, use and reuse of data in a Work; vi. database rights (such as those arising under Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, and under any national implementation thereof, including any amended or successor version of such directive); and vii. other similar, equivalent or corresponding rights throughout the world based on applicable law or treaty, and any national implementations thereof. 2. Waiver. To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer's Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer's heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer's express Statement of Purpose. 3. Public License Fallback. Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer's express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer's Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer's express Statement of Purpose. 4. Limitations and Disclaimers. a. No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, licensed or otherwise affected by this document. b. Affirmer offers the Work as-is and makes no representations or warranties of any kind concerning the Work, express, implied, statutory or otherwise, including without limitation warranties of title, merchantability, fitness for a particular purpose, non infringement, or the absence of latent or other defects, accuracy, or the present or absence of errors, whether or not discoverable, all to the greatest extent permissible under applicable law. c. Affirmer disclaims responsibility for clearing rights of other persons that may apply to the Work or any use thereof, including without limitation any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims responsibility for obtaining any necessary consents, permissions or other rights required for any use of the Work. d. Affirmer understands and acknowledges that Creative Commons is not a party to this document and has no duty or obligation with respect to this CC0 or use of the Work. #n53'>53</a> <a id='n54' href='#n54'>54</a> <a id='n55' href='#n55'>55</a> <a id='n56' href='#n56'>56</a> <a id='n57' href='#n57'>57</a> <a id='n58' href='#n58'>58</a> <a id='n59' href='#n59'>59</a> <a id='n60' href='#n60'>60</a> <a id='n61' href='#n61'>61</a> <a id='n62' href='#n62'>62</a> <a id='n63' href='#n63'>63</a> <a id='n64' href='#n64'>64</a> <a id='n65' href='#n65'>65</a> <a id='n66' href='#n66'>66</a> <a id='n67' href='#n67'>67</a> <a id='n68' href='#n68'>68</a> <a id='n69' href='#n69'>69</a> <a id='n70' href='#n70'>70</a> <a id='n71' href='#n71'>71</a> <a id='n72' href='#n72'>72</a> <a id='n73' href='#n73'>73</a> <a id='n74' href='#n74'>74</a> <a id='n75' href='#n75'>75</a> <a id='n76' href='#n76'>76</a> <a id='n77' href='#n77'>77</a> <a id='n78' href='#n78'>78</a> <a id='n79' href='#n79'>79</a> <a id='n80' href='#n80'>80</a> <a id='n81' href='#n81'>81</a> <a id='n82' href='#n82'>82</a> <a id='n83' href='#n83'>83</a> <a id='n84' href='#n84'>84</a> <a id='n85' href='#n85'>85</a> <a id='n86' href='#n86'>86</a> <a id='n87' href='#n87'>87</a> <a id='n88' href='#n88'>88</a> <a id='n89' href='#n89'>89</a> <a id='n90' href='#n90'>90</a> <a id='n91' href='#n91'>91</a> <a id='n92' href='#n92'>92</a> <a id='n93' href='#n93'>93</a> <a id='n94' href='#n94'>94</a> <a id='n95' href='#n95'>95</a> <a id='n96' href='#n96'>96</a> <a id='n97' href='#n97'>97</a> <a id='n98' href='#n98'>98</a> <a id='n99' href='#n99'>99</a> <a id='n100' href='#n100'>100</a> <a id='n101' href='#n101'>101</a> <a id='n102' href='#n102'>102</a> <a id='n103' href='#n103'>103</a> <a id='n104' href='#n104'>104</a> <a id='n105' href='#n105'>105</a> <a id='n106' href='#n106'>106</a> <a id='n107' href='#n107'>107</a> <a id='n108' href='#n108'>108</a> <a id='n109' href='#n109'>109</a> <a id='n110' href='#n110'>110</a> <a id='n111' href='#n111'>111</a> <a id='n112' href='#n112'>112</a> <a id='n113' href='#n113'>113</a> <a id='n114' href='#n114'>114</a> <a id='n115' href='#n115'>115</a> <a id='n116' href='#n116'>116</a> <a id='n117' href='#n117'>117</a> <a id='n118' href='#n118'>118</a> <a id='n119' href='#n119'>119</a> <a id='n120' href='#n120'>120</a> <a id='n121' href='#n121'>121</a> <a id='n122' href='#n122'>122</a> <a id='n123' href='#n123'>123</a> <a id='n124' href='#n124'>124</a> <a id='n125' href='#n125'>125</a> <a id='n126' href='#n126'>126</a> <a id='n127' href='#n127'>127</a> <a id='n128' href='#n128'>128</a> <a id='n129' href='#n129'>129</a> <a id='n130' href='#n130'>130</a> <a id='n131' href='#n131'>131</a> <a id='n132' href='#n132'>132</a> <a id='n133' href='#n133'>133</a> <a id='n134' href='#n134'>134</a> <a id='n135' href='#n135'>135</a> <a id='n136' href='#n136'>136</a> <a id='n137' href='#n137'>137</a> <a id='n138' href='#n138'>138</a> <a id='n139' href='#n139'>139</a> <a id='n140' href='#n140'>140</a> <a id='n141' href='#n141'>141</a> <a id='n142' href='#n142'>142</a> <a id='n143' href='#n143'>143</a> <a id='n144' href='#n144'>144</a> <a id='n145' href='#n145'>145</a> <a id='n146' href='#n146'>146</a> <a id='n147' href='#n147'>147</a> <a id='n148' href='#n148'>148</a> <a id='n149' href='#n149'>149</a> <a id='n150' href='#n150'>150</a> <a id='n151' href='#n151'>151</a> <a id='n152' href='#n152'>152</a> <a id='n153' href='#n153'>153</a> <a id='n154' href='#n154'>154</a> <a id='n155' href='#n155'>155</a> <a id='n156' href='#n156'>156</a> <a id='n157' href='#n157'>157</a> <a id='n158' href='#n158'>158</a> <a id='n159' href='#n159'>159</a> <a id='n160' href='#n160'>160</a> <a id='n161' href='#n161'>161</a> <a id='n162' href='#n162'>162</a> <a id='n163' href='#n163'>163</a> <a id='n164' href='#n164'>164</a> <a id='n165' href='#n165'>165</a> <a id='n166' href='#n166'>166</a> <a id='n167' href='#n167'>167</a> <a id='n168' href='#n168'>168</a> <a id='n169' href='#n169'>169</a> <a id='n170' href='#n170'>170</a> <a id='n171' href='#n171'>171</a> <a id='n172' href='#n172'>172</a> <a id='n173' href='#n173'>173</a> <a id='n174' href='#n174'>174</a> <a id='n175' href='#n175'>175</a> <a id='n176' href='#n176'>176</a> <a id='n177' href='#n177'>177</a> <a id='n178' href='#n178'>178</a> <a id='n179' href='#n179'>179</a> <a id='n180' href='#n180'>180</a> <a id='n181' href='#n181'>181</a> <a id='n182' href='#n182'>182</a> <a id='n183' href='#n183'>183</a> <a id='n184' href='#n184'>184</a> <a id='n185' href='#n185'>185</a> <a id='n186' href='#n186'>186</a> <a id='n187' href='#n187'>187</a> <a id='n188' href='#n188'>188</a> <a id='n189' href='#n189'>189</a> <a id='n190' href='#n190'>190</a> <a id='n191' href='#n191'>191</a> <a id='n192' href='#n192'>192</a> <a id='n193' href='#n193'>193</a> <a id='n194' href='#n194'>194</a> <a id='n195' href='#n195'>195</a> <a id='n196' href='#n196'>196</a> <a id='n197' href='#n197'>197</a> <a id='n198' href='#n198'>198</a> <a id='n199' href='#n199'>199</a> <a id='n200' href='#n200'>200</a> <a id='n201' href='#n201'>201</a> <a id='n202' href='#n202'>202</a> <a id='n203' href='#n203'>203</a> <a id='n204' href='#n204'>204</a> <a id='n205' href='#n205'>205</a> <a id='n206' href='#n206'>206</a> <a id='n207' href='#n207'>207</a> <a id='n208' href='#n208'>208</a> <a id='n209' href='#n209'>209</a> <a id='n210' href='#n210'>210</a> <a id='n211' href='#n211'>211</a> <a id='n212' href='#n212'>212</a> <a id='n213' href='#n213'>213</a> <a id='n214' href='#n214'>214</a> <a id='n215' href='#n215'>215</a> <a id='n216' href='#n216'>216</a> <a id='n217' href='#n217'>217</a> <a id='n218' href='#n218'>218</a> <a id='n219' href='#n219'>219</a> <a id='n220' href='#n220'>220</a> <a id='n221' href='#n221'>221</a> <a id='n222' href='#n222'>222</a> <a id='n223' href='#n223'>223</a> <a id='n224' href='#n224'>224</a> <a id='n225' href='#n225'>225</a> <a id='n226' href='#n226'>226</a> <a id='n227' href='#n227'>227</a> <a id='n228' href='#n228'>228</a> <a id='n229' href='#n229'>229</a> <a id='n230' href='#n230'>230</a> <a id='n231' href='#n231'>231</a> <a id='n232' href='#n232'>232</a> <a id='n233' href='#n233'>233</a> <a id='n234' href='#n234'>234</a> <a id='n235' href='#n235'>235</a> <a id='n236' href='#n236'>236</a> <a id='n237' href='#n237'>237</a> <a id='n238' href='#n238'>238</a> <a id='n239' href='#n239'>239</a> <a id='n240' href='#n240'>240</a> <a id='n241' href='#n241'>241</a> <a id='n242' href='#n242'>242</a> <a id='n243' href='#n243'>243</a> <a id='n244' href='#n244'>244</a> <a id='n245' href='#n245'>245</a> <a id='n246' href='#n246'>246</a> <a id='n247' href='#n247'>247</a> <a id='n248' href='#n248'>248</a> <a id='n249' href='#n249'>249</a> <a id='n250' href='#n250'>250</a> <a id='n251' href='#n251'>251</a> <a id='n252' href='#n252'>252</a> <a id='n253' href='#n253'>253</a> <a id='n254' href='#n254'>254</a> <a id='n255' href='#n255'>255</a> <a id='n256' href='#n256'>256</a> <a id='n257' href='#n257'>257</a> <a id='n258' href='#n258'>258</a> <a id='n259' href='#n259'>259</a> <a id='n260' href='#n260'>260</a> <a id='n261' href='#n261'>261</a> <a id='n262' href='#n262'>262</a> <a id='n263' href='#n263'>263</a> <a id='n264' href='#n264'>264</a> <a id='n265' href='#n265'>265</a> <a id='n266' href='#n266'>266</a> <a id='n267' href='#n267'>267</a> <a id='n268' href='#n268'>268</a> <a id='n269' href='#n269'>269</a> <a id='n270' href='#n270'>270</a> <a id='n271' href='#n271'>271</a> <a id='n272' href='#n272'>272</a> <a id='n273' href='#n273'>273</a> <a id='n274' href='#n274'>274</a> <a id='n275' href='#n275'>275</a> <a id='n276' href='#n276'>276</a> <a id='n277' href='#n277'>277</a> <a id='n278' href='#n278'>278</a> <a id='n279' href='#n279'>279</a> <a id='n280' href='#n280'>280</a> <a id='n281' href='#n281'>281</a> <a id='n282' href='#n282'>282</a> <a id='n283' href='#n283'>283</a> <a id='n284' href='#n284'>284</a> <a id='n285' href='#n285'>285</a> <a id='n286' href='#n286'>286</a> <a id='n287' href='#n287'>287</a> <a id='n288' href='#n288'>288</a> <a id='n289' href='#n289'>289</a> <a id='n290' href='#n290'>290</a> <a id='n291' href='#n291'>291</a> <a id='n292' href='#n292'>292</a> <a id='n293' href='#n293'>293</a> <a id='n294' href='#n294'>294</a> <a id='n295' href='#n295'>295</a> <a id='n296' href='#n296'>296</a> <a id='n297' href='#n297'>297</a> <a id='n298' href='#n298'>298</a> <a id='n299' href='#n299'>299</a> <a id='n300' href='#n300'>300</a> <a id='n301' href='#n301'>301</a> <a id='n302' href='#n302'>302</a> <a id='n303' href='#n303'>303</a> <a id='n304' href='#n304'>304</a> <a id='n305' href='#n305'>305</a> <a id='n306' href='#n306'>306</a> <a id='n307' href='#n307'>307</a> <a id='n308' href='#n308'>308</a> <a id='n309' href='#n309'>309</a> <a id='n310' href='#n310'>310</a> <a id='n311' href='#n311'>311</a> <a id='n312' href='#n312'>312</a> <a id='n313' href='#n313'>313</a> <a id='n314' href='#n314'>314</a> <a id='n315' href='#n315'>315</a> <a id='n316' href='#n316'>316</a> <a id='n317' href='#n317'>317</a> <a id='n318' href='#n318'>318</a> <a id='n319' href='#n319'>319</a> <a id='n320' href='#n320'>320</a> <a id='n321' href='#n321'>321</a> <a id='n322' href='#n322'>322</a> <a id='n323' href='#n323'>323</a> <a id='n324' href='#n324'>324</a> <a id='n325' href='#n325'>325</a> <a id='n326' href='#n326'>326</a> <a id='n327' href='#n327'>327</a> <a id='n328' href='#n328'>328</a> <a id='n329' href='#n329'>329</a> <a id='n330' href='#n330'>330</a> <a id='n331' href='#n331'>331</a> <a id='n332' href='#n332'>332</a> <a id='n333' href='#n333'>333</a> <a id='n334' href='#n334'>334</a> <a id='n335' href='#n335'>335</a> <a id='n336' href='#n336'>336</a> <a id='n337' href='#n337'>337</a> <a id='n338' href='#n338'>338</a> <a id='n339' href='#n339'>339</a> <a id='n340' href='#n340'>340</a> <a id='n341' href='#n341'>341</a> <a id='n342' href='#n342'>342</a> <a id='n343' href='#n343'>343</a> <a id='n344' href='#n344'>344</a> <a id='n345' href='#n345'>345</a> <a id='n346' href='#n346'>346</a> <a id='n347' href='#n347'>347</a> <a id='n348' href='#n348'>348</a> <a id='n349' href='#n349'>349</a> <a id='n350' href='#n350'>350</a> <a id='n351' href='#n351'>351</a> <a id='n352' href='#n352'>352</a> <a id='n353' href='#n353'>353</a> <a id='n354' href='#n354'>354</a> <a id='n355' href='#n355'>355</a> <a id='n356' href='#n356'>356</a> <a id='n357' href='#n357'>357</a> <a id='n358' href='#n358'>358</a> <a id='n359' href='#n359'>359</a> <a id='n360' href='#n360'>360</a> <a id='n361' href='#n361'>361</a> <a id='n362' href='#n362'>362</a> <a id='n363' href='#n363'>363</a> <a id='n364' href='#n364'>364</a> <a id='n365' href='#n365'>365</a> <a id='n366' href='#n366'>366</a> <a id='n367' href='#n367'>367</a> <a id='n368' href='#n368'>368</a> <a id='n369' href='#n369'>369</a> <a id='n370' href='#n370'>370</a> <a id='n371' href='#n371'>371</a> <a id='n372' href='#n372'>372</a> <a id='n373' href='#n373'>373</a> <a id='n374' href='#n374'>374</a> <a id='n375' href='#n375'>375</a> <a id='n376' href='#n376'>376</a> <a id='n377' href='#n377'>377</a> <a id='n378' href='#n378'>378</a> <a id='n379' href='#n379'>379</a> <a id='n380' href='#n380'>380</a> <a id='n381' href='#n381'>381</a> <a id='n382' href='#n382'>382</a> <a id='n383' href='#n383'>383</a> <a id='n384' href='#n384'>384</a> <a id='n385' href='#n385'>385</a> <a id='n386' href='#n386'>386</a> <a id='n387' href='#n387'>387</a> <a id='n388' href='#n388'>388</a> <a id='n389' href='#n389'>389</a> <a id='n390' href='#n390'>390</a> <a id='n391' href='#n391'>391</a> <a id='n392' href='#n392'>392</a> <a id='n393' href='#n393'>393</a> <a id='n394' href='#n394'>394</a> <a id='n395' href='#n395'>395</a> <a id='n396' href='#n396'>396</a> <a id='n397' href='#n397'>397</a> <a id='n398' href='#n398'>398</a> <a id='n399' href='#n399'>399</a> <a id='n400' href='#n400'>400</a> <a id='n401' href='#n401'>401</a> <a id='n402' href='#n402'>402</a> <a id='n403' href='#n403'>403</a> <a id='n404' href='#n404'>404</a> <a id='n405' href='#n405'>405</a> <a id='n406' href='#n406'>406</a> <a id='n407' href='#n407'>407</a> <a id='n408' href='#n408'>408</a> <a id='n409' href='#n409'>409</a> <a id='n410' href='#n410'>410</a> <a id='n411' href='#n411'>411</a> <a id='n412' href='#n412'>412</a> <a id='n413' href='#n413'>413</a> <a id='n414' href='#n414'>414</a> <a id='n415' href='#n415'>415</a> <a id='n416' href='#n416'>416</a> <a id='n417' href='#n417'>417</a> <a id='n418' href='#n418'>418</a> <a id='n419' href='#n419'>419</a> <a id='n420' href='#n420'>420</a> <a id='n421' href='#n421'>421</a> <a id='n422' href='#n422'>422</a> <a id='n423' href='#n423'>423</a> <a id='n424' href='#n424'>424</a> <a id='n425' href='#n425'>425</a> <a id='n426' href='#n426'>426</a> <a id='n427' href='#n427'>427</a> <a id='n428' href='#n428'>428</a> <a id='n429' href='#n429'>429</a> <a id='n430' href='#n430'>430</a> <a id='n431' href='#n431'>431</a> <a id='n432' href='#n432'>432</a> <a id='n433' href='#n433'>433</a> <a id='n434' href='#n434'>434</a> <a id='n435' href='#n435'>435</a> <a id='n436' href='#n436'>436</a> <a id='n437' href='#n437'>437</a> <a id='n438' href='#n438'>438</a> <a id='n439' href='#n439'>439</a> <a id='n440' href='#n440'>440</a> <a id='n441' href='#n441'>441</a> <a id='n442' href='#n442'>442</a> <a id='n443' href='#n443'>443</a> <a id='n444' href='#n444'>444</a> <a id='n445' href='#n445'>445</a> <a id='n446' href='#n446'>446</a> <a id='n447' href='#n447'>447</a> <a id='n448' href='#n448'>448</a> <a id='n449' href='#n449'>449</a> <a id='n450' href='#n450'>450</a> <a id='n451' href='#n451'>451</a> <a id='n452' href='#n452'>452</a> <a id='n453' href='#n453'>453</a> <a id='n454' href='#n454'>454</a> <a id='n455' href='#n455'>455</a> <a id='n456' href='#n456'>456</a> <a id='n457' href='#n457'>457</a> <a id='n458' href='#n458'>458</a> <a id='n459' href='#n459'>459</a> <a id='n460' href='#n460'>460</a> <a id='n461' href='#n461'>461</a> <a id='n462' href='#n462'>462</a> <a id='n463' href='#n463'>463</a> <a id='n464' href='#n464'>464</a> <a id='n465' href='#n465'>465</a> <a id='n466' href='#n466'>466</a> <a id='n467' href='#n467'>467</a> <a id='n468' href='#n468'>468</a> <a id='n469' href='#n469'>469</a> <a id='n470' href='#n470'>470</a> <a id='n471' href='#n471'>471</a> <a id='n472' href='#n472'>472</a> <a id='n473' href='#n473'>473</a> <a id='n474' href='#n474'>474</a> <a id='n475' href='#n475'>475</a> <a id='n476' href='#n476'>476</a> <a id='n477' href='#n477'>477</a> <a id='n478' href='#n478'>478</a> <a id='n479' href='#n479'>479</a> <a id='n480' href='#n480'>480</a> <a id='n481' href='#n481'>481</a> <a id='n482' href='#n482'>482</a> <a id='n483' href='#n483'>483</a> <a id='n484' href='#n484'>484</a> <a id='n485' href='#n485'>485</a> <a id='n486' href='#n486'>486</a> <a id='n487' href='#n487'>487</a> <a id='n488' href='#n488'>488</a> <a id='n489' href='#n489'>489</a> <a id='n490' href='#n490'>490</a> <a id='n491' href='#n491'>491</a> <a id='n492' href='#n492'>492</a> <a id='n493' href='#n493'>493</a> <a id='n494' href='#n494'>494</a> <a id='n495' href='#n495'>495</a> <a id='n496' href='#n496'>496</a> <a id='n497' href='#n497'>497</a> <a id='n498' href='#n498'>498</a> <a id='n499' href='#n499'>499</a> <a id='n500' href='#n500'>500</a> <a id='n501' href='#n501'>501</a> <a id='n502' href='#n502'>502</a> <a id='n503' href='#n503'>503</a> <a id='n504' href='#n504'>504</a> <a id='n505' href='#n505'>505</a> <a id='n506' href='#n506'>506</a> <a id='n507' href='#n507'>507</a> <a id='n508' href='#n508'>508</a> <a id='n509' href='#n509'>509</a> <a id='n510' href='#n510'>510</a> <a id='n511' href='#n511'>511</a> <a id='n512' href='#n512'>512</a> <a id='n513' href='#n513'>513</a> <a id='n514' href='#n514'>514</a> <a id='n515' href='#n515'>515</a> <a id='n516' href='#n516'>516</a> <a id='n517' href='#n517'>517</a> <a id='n518' href='#n518'>518</a> <a id='n519' href='#n519'>519</a> <a id='n520' href='#n520'>520</a> <a id='n521' href='#n521'>521</a> <a id='n522' href='#n522'>522</a> <a id='n523' href='#n523'>523</a> <a id='n524' href='#n524'>524</a> <a id='n525' href='#n525'>525</a> <a id='n526' href='#n526'>526</a> <a id='n527' href='#n527'>527</a> <a id='n528' href='#n528'>528</a> <a id='n529' href='#n529'>529</a> <a id='n530' href='#n530'>530</a> <a id='n531' href='#n531'>531</a> <a id='n532' href='#n532'>532</a> <a id='n533' href='#n533'>533</a> <a id='n534' href='#n534'>534</a> <a id='n535' href='#n535'>535</a> <a id='n536' href='#n536'>536</a> <a id='n537' href='#n537'>537</a> <a id='n538' href='#n538'>538</a> <a id='n539' href='#n539'>539</a> <a id='n540' href='#n540'>540</a> <a id='n541' href='#n541'>541</a> <a id='n542' href='#n542'>542</a> <a id='n543' href='#n543'>543</a> <a id='n544' href='#n544'>544</a> <a id='n545' href='#n545'>545</a> <a id='n546' href='#n546'>546</a> <a id='n547' href='#n547'>547</a> <a id='n548' href='#n548'>548</a> <a id='n549' href='#n549'>549</a> <a id='n550' href='#n550'>550</a> <a id='n551' href='#n551'>551</a> <a id='n552' href='#n552'>552</a> <a id='n553' href='#n553'>553</a> <a id='n554' href='#n554'>554</a> <a id='n555' href='#n555'>555</a> <a id='n556' href='#n556'>556</a> <a id='n557' href='#n557'>557</a> <a id='n558' href='#n558'>558</a> <a id='n559' href='#n559'>559</a> <a id='n560' href='#n560'>560</a> <a id='n561' href='#n561'>561</a> <a id='n562' href='#n562'>562</a> <a id='n563' href='#n563'>563</a> <a id='n564' href='#n564'>564</a> <a id='n565' href='#n565'>565</a> <a id='n566' href='#n566'>566</a> <a id='n567' href='#n567'>567</a> <a id='n568' href='#n568'>568</a> <a id='n569' href='#n569'>569</a> <a id='n570' href='#n570'>570</a> <a id='n571' href='#n571'>571</a> <a id='n572' href='#n572'>572</a> <a id='n573' href='#n573'>573</a> <a id='n574' href='#n574'>574</a> <a id='n575' href='#n575'>575</a> <a id='n576' href='#n576'>576</a> <a id='n577' href='#n577'>577</a> <a id='n578' href='#n578'>578</a> <a id='n579' href='#n579'>579</a> <a id='n580' href='#n580'>580</a> <a id='n581' href='#n581'>581</a> <a id='n582' href='#n582'>582</a> <a id='n583' href='#n583'>583</a> <a id='n584' href='#n584'>584</a> <a id='n585' href='#n585'>585</a> <a id='n586' href='#n586'>586</a> <a id='n587' href='#n587'>587</a> <a id='n588' href='#n588'>588</a> <a id='n589' href='#n589'>589</a> <a id='n590' href='#n590'>590</a> <a id='n591' href='#n591'>591</a> <a id='n592' href='#n592'>592</a> <a id='n593' href='#n593'>593</a> <a id='n594' href='#n594'>594</a> <a id='n595' href='#n595'>595</a> <a id='n596' href='#n596'>596</a> <a id='n597' href='#n597'>597</a> <a id='n598' href='#n598'>598</a> <a id='n599' href='#n599'>599</a> <a id='n600' href='#n600'>600</a> <a id='n601' href='#n601'>601</a> <a id='n602' href='#n602'>602</a> <a id='n603' href='#n603'>603</a> <a id='n604' href='#n604'>604</a> <a id='n605' href='#n605'>605</a> <a id='n606' href='#n606'>606</a> <a id='n607' href='#n607'>607</a> <a id='n608' href='#n608'>608</a> <a id='n609' href='#n609'>609</a> <a id='n610' href='#n610'>610</a> <a id='n611' href='#n611'>611</a> <a id='n612' href='#n612'>612</a> <a id='n613' href='#n613'>613</a> <a id='n614' href='#n614'>614</a> <a id='n615' href='#n615'>615</a> <a id='n616' href='#n616'>616</a> <a id='n617' href='#n617'>617</a> <a id='n618' href='#n618'>618</a> <a id='n619' href='#n619'>619</a> <a id='n620' href='#n620'>620</a> <a id='n621' href='#n621'>621</a> <a id='n622' href='#n622'>622</a> <a id='n623' href='#n623'>623</a> <a id='n624' href='#n624'>624</a> <a id='n625' href='#n625'>625</a> <a id='n626' href='#n626'>626</a> <a id='n627' href='#n627'>627</a> <a id='n628' href='#n628'>628</a> <a id='n629' href='#n629'>629</a> <a id='n630' href='#n630'>630</a> <a id='n631' href='#n631'>631</a> <a id='n632' href='#n632'>632</a> <a id='n633' href='#n633'>633</a> <a id='n634' href='#n634'>634</a> <a id='n635' href='#n635'>635</a> <a id='n636' href='#n636'>636</a> <a id='n637' href='#n637'>637</a> <a id='n638' href='#n638'>638</a> <a id='n639' href='#n639'>639</a> <a id='n640' href='#n640'>640</a> <a id='n641' href='#n641'>641</a> <a id='n642' href='#n642'>642</a> <a id='n643' href='#n643'>643</a> <a id='n644' href='#n644'>644</a> <a id='n645' href='#n645'>645</a> <a id='n646' href='#n646'>646</a> <a id='n647' href='#n647'>647</a> <a id='n648' href='#n648'>648</a> <a id='n649' href='#n649'>649</a> <a id='n650' href='#n650'>650</a> <a id='n651' href='#n651'>651</a> <a id='n652' href='#n652'>652</a> <a id='n653' href='#n653'>653</a> <a id='n654' href='#n654'>654</a> <a id='n655' href='#n655'>655</a> <a id='n656' href='#n656'>656</a> <a id='n657' href='#n657'>657</a> <a id='n658' href='#n658'>658</a> <a id='n659' href='#n659'>659</a> <a id='n660' href='#n660'>660</a> <a id='n661' href='#n661'>661</a> <a id='n662' href='#n662'>662</a> <a id='n663' href='#n663'>663</a> <a id='n664' href='#n664'>664</a> <a id='n665' href='#n665'>665</a> <a id='n666' href='#n666'>666</a> <a id='n667' href='#n667'>667</a> <a id='n668' href='#n668'>668</a> <a id='n669' href='#n669'>669</a> <a id='n670' href='#n670'>670</a> <a id='n671' href='#n671'>671</a> <a id='n672' href='#n672'>672</a> <a id='n673' href='#n673'>673</a> <a id='n674' href='#n674'>674</a> <a id='n675' href='#n675'>675</a> <a id='n676' href='#n676'>676</a> <a id='n677' href='#n677'>677</a> <a id='n678' href='#n678'>678</a> <a id='n679' href='#n679'>679</a> <a id='n680' href='#n680'>680</a> <a id='n681' href='#n681'>681</a> <a id='n682' href='#n682'>682</a> <a id='n683' href='#n683'>683</a> <a id='n684' href='#n684'>684</a> <a id='n685' href='#n685'>685</a> <a id='n686' href='#n686'>686</a> <a id='n687' href='#n687'>687</a> <a id='n688' href='#n688'>688</a> <a id='n689' href='#n689'>689</a> <a id='n690' href='#n690'>690</a> <a id='n691' href='#n691'>691</a> <a id='n692' href='#n692'>692</a> <a id='n693' href='#n693'>693</a> <a id='n694' href='#n694'>694</a> <a id='n695' href='#n695'>695</a> <a id='n696' href='#n696'>696</a> <a id='n697' href='#n697'>697</a> <a id='n698' href='#n698'>698</a> <a id='n699' href='#n699'>699</a> <a id='n700' href='#n700'>700</a> <a id='n701' href='#n701'>701</a> <a id='n702' href='#n702'>702</a> <a id='n703' href='#n703'>703</a> <a id='n704' href='#n704'>704</a> <a id='n705' href='#n705'>705</a> <a id='n706' href='#n706'>706</a> <a id='n707' href='#n707'>707</a> <a id='n708' href='#n708'>708</a> <a id='n709' href='#n709'>709</a> <a id='n710' href='#n710'>710</a> <a id='n711' href='#n711'>711</a> <a id='n712' href='#n712'>712</a> <a id='n713' href='#n713'>713</a> <a id='n714' href='#n714'>714</a> <a id='n715' href='#n715'>715</a> <a id='n716' href='#n716'>716</a> <a id='n717' href='#n717'>717</a> <a id='n718' href='#n718'>718</a> <a id='n719' href='#n719'>719</a> <a id='n720' href='#n720'>720</a> <a id='n721' href='#n721'>721</a> <a id='n722' href='#n722'>722</a> <a id='n723' href='#n723'>723</a> <a id='n724' href='#n724'>724</a> <a id='n725' href='#n725'>725</a> <a id='n726' href='#n726'>726</a> <a id='n727' href='#n727'>727</a> <a id='n728' href='#n728'>728</a> <a id='n729' href='#n729'>729</a> <a id='n730' href='#n730'>730</a> <a id='n731' href='#n731'>731</a> <a id='n732' href='#n732'>732</a> <a id='n733' href='#n733'>733</a> <a id='n734' href='#n734'>734</a> <a id='n735' href='#n735'>735</a> <a id='n736' href='#n736'>736</a> <a id='n737' href='#n737'>737</a> <a id='n738' href='#n738'>738</a> <a id='n739' href='#n739'>739</a> <a id='n740' href='#n740'>740</a> <a id='n741' href='#n741'>741</a> <a id='n742' href='#n742'>742</a> <a id='n743' href='#n743'>743</a> <a id='n744' href='#n744'>744</a> <a id='n745' href='#n745'>745</a> <a id='n746' href='#n746'>746</a> <a id='n747' href='#n747'>747</a> <a id='n748' href='#n748'>748</a> <a id='n749' href='#n749'>749</a> <a id='n750' href='#n750'>750</a> <a id='n751' href='#n751'>751</a> <a id='n752' href='#n752'>752</a> <a id='n753' href='#n753'>753</a> <a id='n754' href='#n754'>754</a> <a id='n755' href='#n755'>755</a> <a id='n756' href='#n756'>756</a> <a id='n757' href='#n757'>757</a> <a id='n758' href='#n758'>758</a> <a id='n759' href='#n759'>759</a> <a id='n760' href='#n760'>760</a> <a id='n761' href='#n761'>761</a> <a id='n762' href='#n762'>762</a> <a id='n763' href='#n763'>763</a> <a id='n764' href='#n764'>764</a> <a id='n765' href='#n765'>765</a> <a id='n766' href='#n766'>766</a> <a id='n767' href='#n767'>767</a> <a id='n768' href='#n768'>768</a> <a id='n769' href='#n769'>769</a> <a id='n770' href='#n770'>770</a> <a id='n771' href='#n771'>771</a> <a id='n772' href='#n772'>772</a> <a id='n773' href='#n773'>773</a> <a id='n774' href='#n774'>774</a> <a id='n775' href='#n775'>775</a> <a id='n776' href='#n776'>776</a> <a id='n777' href='#n777'>777</a> <a id='n778' href='#n778'>778</a> <a id='n779' href='#n779'>779</a> <a id='n780' href='#n780'>780</a> <a id='n781' href='#n781'>781</a> <a id='n782' href='#n782'>782</a> <a id='n783' href='#n783'>783</a> <a id='n784' href='#n784'>784</a> <a id='n785' href='#n785'>785</a> <a id='n786' href='#n786'>786</a> <a id='n787' href='#n787'>787</a> <a id='n788' href='#n788'>788</a> <a id='n789' href='#n789'>789</a> <a id='n790' href='#n790'>790</a> <a id='n791' href='#n791'>791</a> <a id='n792' href='#n792'>792</a> <a id='n793' href='#n793'>793</a> <a id='n794' href='#n794'>794</a> <a id='n795' href='#n795'>795</a> <a id='n796' href='#n796'>796</a> <a id='n797' href='#n797'>797</a> <a id='n798' href='#n798'>798</a> <a id='n799' href='#n799'>799</a> <a id='n800' href='#n800'>800</a> <a id='n801' href='#n801'>801</a> <a id='n802' href='#n802'>802</a> <a id='n803' href='#n803'>803</a> <a id='n804' href='#n804'>804</a> <a id='n805' href='#n805'>805</a> <a id='n806' href='#n806'>806</a> <a id='n807' href='#n807'>807</a> <a id='n808' href='#n808'>808</a> <a id='n809' href='#n809'>809</a> <a id='n810' href='#n810'>810</a> <a id='n811' href='#n811'>811</a> <a id='n812' href='#n812'>812</a> <a id='n813' href='#n813'>813</a> <a id='n814' href='#n814'>814</a> <a id='n815' href='#n815'>815</a> <a id='n816' href='#n816'>816</a> <a id='n817' href='#n817'>817</a> <a id='n818' href='#n818'>818</a> <a id='n819' href='#n819'>819</a> <a id='n820' href='#n820'>820</a> <a id='n821' href='#n821'>821</a> <a id='n822' href='#n822'>822</a> <a id='n823' href='#n823'>823</a> <a id='n824' href='#n824'>824</a> <a id='n825' href='#n825'>825</a> <a id='n826' href='#n826'>826</a> <a id='n827' href='#n827'>827</a> <a id='n828' href='#n828'>828</a> <a id='n829' href='#n829'>829</a> <a id='n830' href='#n830'>830</a> <a id='n831' href='#n831'>831</a> <a id='n832' href='#n832'>832</a> <a id='n833' href='#n833'>833</a> <a id='n834' href='#n834'>834</a> <a id='n835' href='#n835'>835</a> <a id='n836' href='#n836'>836</a> <a id='n837' href='#n837'>837</a> <a id='n838' href='#n838'>838</a> <a id='n839' href='#n839'>839</a> <a id='n840' href='#n840'>840</a> <a id='n841' href='#n841'>841</a> <a id='n842' href='#n842'>842</a> <a id='n843' href='#n843'>843</a> <a id='n844' href='#n844'>844</a> <a id='n845' href='#n845'>845</a> <a id='n846' href='#n846'>846</a> <a id='n847' href='#n847'>847</a> <a id='n848' href='#n848'>848</a> <a id='n849' href='#n849'>849</a> <a id='n850' href='#n850'>850</a> <a id='n851' href='#n851'>851</a> <a id='n852' href='#n852'>852</a> <a id='n853' href='#n853'>853</a> <a id='n854' href='#n854'>854</a> <a id='n855' href='#n855'>855</a> <a id='n856' href='#n856'>856</a> <a id='n857' href='#n857'>857</a> <a id='n858' href='#n858'>858</a> <a id='n859' href='#n859'>859</a> <a id='n860' href='#n860'>860</a> <a id='n861' href='#n861'>861</a> <a id='n862' href='#n862'>862</a> <a id='n863' href='#n863'>863</a> <a id='n864' href='#n864'>864</a> <a id='n865' href='#n865'>865</a> <a id='n866' href='#n866'>866</a> <a id='n867' href='#n867'>867</a> <a id='n868' href='#n868'>868</a> <a id='n869' href='#n869'>869</a> <a id='n870' href='#n870'>870</a> <a id='n871' href='#n871'>871</a> <a id='n872' href='#n872'>872</a> <a id='n873' href='#n873'>873</a> <a id='n874' href='#n874'>874</a> <a id='n875' href='#n875'>875</a> <a id='n876' href='#n876'>876</a> <a id='n877' href='#n877'>877</a> <a id='n878' href='#n878'>878</a> <a id='n879' href='#n879'>879</a> <a id='n880' href='#n880'>880</a> <a id='n881' href='#n881'>881</a> <a id='n882' href='#n882'>882</a> <a id='n883' href='#n883'>883</a> <a id='n884' href='#n884'>884</a> <a id='n885' href='#n885'>885</a> <a id='n886' href='#n886'>886</a> <a id='n887' href='#n887'>887</a> <a id='n888' href='#n888'>888</a> <a id='n889' href='#n889'>889</a> <a id='n890' href='#n890'>890</a> <a id='n891' href='#n891'>891</a> <a id='n892' href='#n892'>892</a> <a id='n893' href='#n893'>893</a> <a id='n894' href='#n894'>894</a> <a id='n895' href='#n895'>895</a> <a id='n896' href='#n896'>896</a> <a id='n897' href='#n897'>897</a> <a id='n898' href='#n898'>898</a> <a id='n899' href='#n899'>899</a> <a id='n900' href='#n900'>900</a> <a id='n901' href='#n901'>901</a> <a id='n902' href='#n902'>902</a> <a id='n903' href='#n903'>903</a> <a id='n904' href='#n904'>904</a> <a id='n905' href='#n905'>905</a> <a id='n906' href='#n906'>906</a> <a id='n907' href='#n907'>907</a> <a id='n908' href='#n908'>908</a> <a id='n909' href='#n909'>909</a> <a id='n910' href='#n910'>910</a> <a id='n911' href='#n911'>911</a> <a id='n912' href='#n912'>912</a> <a id='n913' href='#n913'>913</a> <a id='n914' href='#n914'>914</a> <a id='n915' href='#n915'>915</a> <a id='n916' href='#n916'>916</a> <a id='n917' href='#n917'>917</a> <a id='n918' href='#n918'>918</a> <a id='n919' href='#n919'>919</a> <a id='n920' href='#n920'>920</a> <a id='n921' href='#n921'>921</a> <a id='n922' href='#n922'>922</a> <a id='n923' href='#n923'>923</a> <a id='n924' href='#n924'>924</a> <a id='n925' href='#n925'>925</a> <a id='n926' href='#n926'>926</a> <a id='n927' href='#n927'>927</a> <a id='n928' href='#n928'>928</a> <a id='n929' href='#n929'>929</a> <a id='n930' href='#n930'>930</a> <a id='n931' href='#n931'>931</a> <a id='n932' href='#n932'>932</a> <a id='n933' href='#n933'>933</a> <a id='n934' href='#n934'>934</a> <a id='n935' href='#n935'>935</a> <a id='n936' href='#n936'>936</a> <a id='n937' href='#n937'>937</a> <a id='n938' href='#n938'>938</a> <a id='n939' href='#n939'>939</a> <a id='n940' href='#n940'>940</a> <a id='n941' href='#n941'>941</a> <a id='n942' href='#n942'>942</a> <a id='n943' href='#n943'>943</a> <a id='n944' href='#n944'>944</a> <a id='n945' href='#n945'>945</a> <a id='n946' href='#n946'>946</a> <a id='n947' href='#n947'>947</a> <a id='n948' href='#n948'>948</a> <a id='n949' href='#n949'>949</a> <a id='n950' href='#n950'>950</a> <a id='n951' href='#n951'>951</a> <a id='n952' href='#n952'>952</a> <a id='n953' href='#n953'>953</a> <a id='n954' href='#n954'>954</a> <a id='n955' href='#n955'>955</a> <a id='n956' href='#n956'>956</a> <a id='n957' href='#n957'>957</a> <a id='n958' href='#n958'>958</a> <a id='n959' href='#n959'>959</a> <a id='n960' href='#n960'>960</a> <a id='n961' href='#n961'>961</a> <a id='n962' href='#n962'>962</a> <a id='n963' href='#n963'>963</a> <a id='n964' href='#n964'>964</a> <a id='n965' href='#n965'>965</a> <a id='n966' href='#n966'>966</a> <a id='n967' href='#n967'>967</a> <a id='n968' href='#n968'>968</a> <a id='n969' href='#n969'>969</a> <a id='n970' href='#n970'>970</a> <a id='n971' href='#n971'>971</a> <a id='n972' href='#n972'>972</a> <a id='n973' href='#n973'>973</a> <a id='n974' href='#n974'>974</a> <a id='n975' href='#n975'>975</a> <a id='n976' href='#n976'>976</a> <a id='n977' href='#n977'>977</a> <a id='n978' href='#n978'>978</a> <a id='n979' href='#n979'>979</a> <a id='n980' href='#n980'>980</a> <a id='n981' href='#n981'>981</a> <a id='n982' href='#n982'>982</a> <a id='n983' href='#n983'>983</a> <a id='n984' href='#n984'>984</a> <a id='n985' href='#n985'>985</a> <a id='n986' href='#n986'>986</a> <a id='n987' href='#n987'>987</a> <a id='n988' href='#n988'>988</a> <a id='n989' href='#n989'>989</a> <a id='n990' href='#n990'>990</a> <a id='n991' href='#n991'>991</a> <a id='n992' href='#n992'>992</a> <a id='n993' href='#n993'>993</a> <a id='n994' href='#n994'>994</a> <a id='n995' href='#n995'>995</a> <a id='n996' href='#n996'>996</a> <a id='n997' href='#n997'>997</a> <a id='n998' href='#n998'>998</a> <a id='n999' href='#n999'>999</a> <a id='n1000' href='#n1000'>1000</a> <a id='n1001' href='#n1001'>1001</a> <a id='n1002' href='#n1002'>1002</a> <a id='n1003' href='#n1003'>1003</a> <a id='n1004' href='#n1004'>1004</a> <a id='n1005' href='#n1005'>1005</a> <a id='n1006' href='#n1006'>1006</a> <a id='n1007' href='#n1007'>1007</a> <a id='n1008' href='#n1008'>1008</a> <a id='n1009' href='#n1009'>1009</a> <a id='n1010' href='#n1010'>1010</a> <a id='n1011' href='#n1011'>1011</a> <a id='n1012' href='#n1012'>1012</a> <a id='n1013' href='#n1013'>1013</a> <a id='n1014' href='#n1014'>1014</a> <a id='n1015' href='#n1015'>1015</a> <a id='n1016' href='#n1016'>1016</a> <a id='n1017' href='#n1017'>1017</a> <a id='n1018' href='#n1018'>1018</a> <a id='n1019' href='#n1019'>1019</a> <a id='n1020' href='#n1020'>1020</a> <a id='n1021' href='#n1021'>1021</a> <a id='n1022' href='#n1022'>1022</a> <a id='n1023' href='#n1023'>1023</a> <a id='n1024' href='#n1024'>1024</a> <a id='n1025' href='#n1025'>1025</a> <a id='n1026' href='#n1026'>1026</a> <a id='n1027' href='#n1027'>1027</a> <a id='n1028' href='#n1028'>1028</a> <a id='n1029' href='#n1029'>1029</a> <a id='n1030' href='#n1030'>1030</a> <a id='n1031' href='#n1031'>1031</a> <a id='n1032' href='#n1032'>1032</a> <a id='n1033' href='#n1033'>1033</a> <a id='n1034' href='#n1034'>1034</a> <a id='n1035' href='#n1035'>1035</a> <a id='n1036' href='#n1036'>1036</a> <a id='n1037' href='#n1037'>1037</a> <a id='n1038' href='#n1038'>1038</a> <a id='n1039' href='#n1039'>1039</a> <a id='n1040' href='#n1040'>1040</a> <a id='n1041' href='#n1041'>1041</a> <a id='n1042' href='#n1042'>1042</a> <a id='n1043' href='#n1043'>1043</a> <a id='n1044' href='#n1044'>1044</a> <a id='n1045' href='#n1045'>1045</a> <a id='n1046' href='#n1046'>1046</a> <a id='n1047' href='#n1047'>1047</a> <a id='n1048' href='#n1048'>1048</a> <a id='n1049' href='#n1049'>1049</a> <a id='n1050' href='#n1050'>1050</a> <a id='n1051' href='#n1051'>1051</a> <a id='n1052' href='#n1052'>1052</a> <a id='n1053' href='#n1053'>1053</a> <a id='n1054' href='#n1054'>1054</a> <a id='n1055' href='#n1055'>1055</a> <a id='n1056' href='#n1056'>1056</a> <a id='n1057' href='#n1057'>1057</a> <a id='n1058' href='#n1058'>1058</a> <a id='n1059' href='#n1059'>1059</a> <a id='n1060' href='#n1060'>1060</a> <a id='n1061' href='#n1061'>1061</a> <a id='n1062' href='#n1062'>1062</a> </pre></td> <td class='lines'><pre><code><span class="hl com">/* SPDX-License-Identifier: LGPL-2.1-or-later */</span> <span class="hl com">/*</span> <span class="hl com"> * Copyright (C) 2019, Google Inc.</span> <span class="hl com"> *</span> <span class="hl com"> * controls.cpp - Control handling</span> <span class="hl com"> */</span> <span class="hl ppc">#include <libcamera/controls.h></span> <span class="hl ppc">#include <iomanip></span> <span class="hl ppc">#include <sstream></span> <span class="hl ppc">#include <string></span> <span class="hl ppc">#include <string.h></span> <span class="hl ppc">#include <libcamera/base/log.h></span> <span class="hl ppc">#include <libcamera/base/utils.h></span> <span class="hl ppc">#include</span> <span class="hl pps">"libcamera/internal/control_validator.h"</span><span class="hl ppc"></span> <span class="hl com">/**</span> <span class="hl com"> * \file controls.h</span> <span class="hl com"> * \brief Framework to manage controls related to an object</span> <span class="hl com"> *</span> <span class="hl com"> * A control is a mean to govern or influence the operation of an object, and in</span> <span class="hl com"> * particular of a camera. Every control is defined by a unique numerical ID, a</span> <span class="hl com"> * name string and the data type of the value it stores. The libcamera API</span> <span class="hl com"> * defines a set of standard controls in the libcamera::controls namespace, as</span> <span class="hl com"> * a set of instances of the Control class.</span> <span class="hl com"> *</span> <span class="hl com"> * The main way for applications to interact with controls is through the</span> <span class="hl com"> * ControlList stored in the Request class:</span> <span class="hl com"> *</span> <span class="hl com"> * \code{.cpp}</span> <span class="hl com"> * Request *req = ...;</span> <span class="hl com"> * ControlList &controls = req->controls();</span> <span class="hl com"> * controls->set(controls::AwbEnable, false);</span> <span class="hl com"> * controls->set(controls::ManualExposure, 1000);</span> <span class="hl com"> *</span> <span class="hl com"> * ...</span> <span class="hl com"> *</span> <span class="hl com"> * int32_t exposure = controls->get(controls::ManualExposure);</span> <span class="hl com"> * \endcode</span> <span class="hl com"> *</span> <span class="hl com"> * The ControlList::get() and ControlList::set() functions automatically deduce</span> <span class="hl com"> * the data type based on the control.</span> <span class="hl com"> */</span> <span class="hl kwa">namespace</span> libcamera <span class="hl opt">{</span> <span class="hl kwd">LOG_DEFINE_CATEGORY</span><span class="hl opt">(</span>Controls<span class="hl opt">)</span> <span class="hl kwa">namespace</span> <span class="hl opt">{</span> <span class="hl kwb">static</span> <span class="hl kwc">constexpr</span> <span class="hl kwb">size_t</span> ControlValueSize<span class="hl opt">[] = {</span> <span class="hl opt">[</span>ControlTypeNone<span class="hl opt">] =</span> <span class="hl num">0</span><span class="hl opt">,</span> <span class="hl opt">[</span>ControlTypeBool<span class="hl opt">] =</span> <span class="hl kwa">sizeof</span><span class="hl opt">(</span><span class="hl kwb">bool</span><span class="hl opt">),</span> <span class="hl opt">[</span>ControlTypeByte<span class="hl opt">] =</span> <span class="hl kwa">sizeof</span><span class="hl opt">(</span><span class="hl kwb">uint8_t</span><span class="hl opt">),</span> <span class="hl opt">[</span>ControlTypeInteger32<span class="hl opt">] =</span> <span class="hl kwa">sizeof</span><span class="hl opt">(</span><span class="hl kwb">int32_t</span><span class="hl opt">),</span> <span class="hl opt">[</span>ControlTypeInteger64<span class="hl opt">] =</span> <span class="hl kwa">sizeof</span><span class="hl opt">(</span><span class="hl kwb">int64_t</span><span class="hl opt">),</span> <span class="hl opt">[</span>ControlTypeFloat<span class="hl opt">] =</span> <span class="hl kwa">sizeof</span><span class="hl opt">(</span><span class="hl kwb">float</span><span class="hl opt">),</span> <span class="hl opt">[</span>ControlTypeString<span class="hl opt">] =</span> <span class="hl kwa">sizeof</span><span class="hl opt">(</span><span class="hl kwb">char</span><span class="hl opt">),</span> <span class="hl opt">[</span>ControlTypeRectangle<span class="hl opt">] =</span> <span class="hl kwa">sizeof</span><span class="hl opt">(</span>Rectangle<span class="hl opt">),</span> <span class="hl opt">[</span>ControlTypeSize<span class="hl opt">] =</span> <span class="hl kwa">sizeof</span><span class="hl opt">(</span>Size<span class="hl opt">),</span> <span class="hl opt">};</span> <span class="hl opt">}</span> <span class="hl com">/* namespace */</span> <span class="hl com">/**</span> <span class="hl com"> * \enum ControlType</span> <span class="hl com"> * \brief Define the data type of a Control</span> <span class="hl com"> * \var ControlTypeNone</span> <span class="hl com"> * Invalid type, for empty values</span> <span class="hl com"> * \var ControlTypeBool</span> <span class="hl com"> * The control stores a boolean value</span> <span class="hl com"> * \var ControlTypeByte</span> <span class="hl com"> * The control stores a byte value as an unsigned 8-bit integer</span> <span class="hl com"> * \var ControlTypeInteger32</span> <span class="hl com"> * The control stores a 32-bit integer value</span> <span class="hl com"> * \var ControlTypeInteger64</span> <span class="hl com"> * The control stores a 64-bit integer value</span> <span class="hl com"> * \var ControlTypeFloat</span> <span class="hl com"> * The control stores a 32-bit floating point value</span> <span class="hl com"> * \var ControlTypeString</span> <span class="hl com"> * The control stores a string value as an array of char</span> <span class="hl com"> */</span> <span class="hl com">/**</span> <span class="hl com"> * \class ControlValue</span> <span class="hl com"> * \brief Abstract type representing the value of a control</span> <span class="hl com"> */</span> <span class="hl com">/** \todo Revisit the ControlValue layout when stabilizing the ABI */</span> <span class="hl kwa">static_assert</span><span class="hl opt">(</span><span class="hl kwa">sizeof</span><span class="hl opt">(</span>ControlValue<span class="hl opt">) ==</span> <span class="hl num">16</span><span class="hl opt">,</span> <span class="hl str">"Invalid size of ControlValue class"</span><span class="hl opt">);</span> <span class="hl com">/**</span> <span class="hl com"> * \brief Construct an empty ControlValue.</span> <span class="hl com"> */</span> <span class="hl kwc">ControlValue</span><span class="hl opt">::</span><span class="hl kwd">ControlValue</span><span class="hl opt">()</span> <span class="hl opt">:</span> <span class="hl kwd">type_</span><span class="hl opt">(</span>ControlTypeNone<span class="hl opt">),</span> <span class="hl kwd">isArray_</span><span class="hl opt">(</span><span class="hl kwa">false</span><span class="hl opt">),</span> <span class="hl kwd">numElements_</span><span class="hl opt">(</span><span class="hl num">0</span><span class="hl opt">)</span> <span class="hl opt">{</span> <span class="hl opt">}</span> <span class="hl com">/**</span> <span class="hl com"> * \fn template<typename T> T ControlValue::ControlValue(const T &value)</span> <span class="hl com"> * \brief Construct a ControlValue of type T</span> <span class="hl com"> * \param[in] value Initial value</span> <span class="hl com"> *</span> <span class="hl com"> * This function constructs a new instance of ControlValue and stores the \a</span> <span class="hl com"> * value inside it. If the type \a T is equivalent to Span<R>, the instance</span> <span class="hl com"> * stores an array of values of type \a R. Otherwise the instance stores a</span> <span class="hl com"> * single value of type \a T. The numElements() and type() are updated to</span> <span class="hl com"> * reflect the stored value.</span> <span class="hl com"> */</span> <span class="hl kwb">void</span> <span class="hl kwc">ControlValue</span><span class="hl opt">::</span><span class="hl kwd">release</span><span class="hl opt">()</span> <span class="hl opt">{</span> <span class="hl kwc">std</span><span class="hl opt">::</span><span class="hl kwb">size_t</span> size <span class="hl opt">=</span> numElements_ <span class="hl opt">*</span> ControlValueSize<span class="hl opt">[</span>type_<span class="hl opt">];</span> <span class="hl kwa">if</span> <span class="hl opt">(</span>size <span class="hl opt">></span> <span class="hl kwa">sizeof</span><span class="hl opt">(</span>value_<span class="hl opt">)) {</span> <span class="hl kwa">delete</span><span class="hl opt">[]</span> <span class="hl kwa">reinterpret_cast</span><span class="hl opt"><</span><span class="hl kwb">uint8_t</span> <span class="hl opt">*>(</span>storage_<span class="hl opt">);</span> storage_ <span class="hl opt">=</span> <span class="hl kwc">nullptr</span><span class="hl opt">;</span> <span class="hl opt">}</span> <span class="hl opt">}</span> <span class="hl kwc">ControlValue</span><span class="hl opt">::~</span><span class="hl kwd">ControlValue</span><span class="hl opt">()</span> <span class="hl opt">{</span> <span class="hl kwd">release</span><span class="hl opt">();</span> <span class="hl opt">}</span> <span class="hl com">/**</span> <span class="hl com"> * \brief Construct a ControlValue with the content of \a other</span> <span class="hl com"> * \param[in] other The ControlValue to copy content from</span> <span class="hl com"> */</span> <span class="hl kwc">ControlValue</span><span class="hl opt">::</span><span class="hl kwd">ControlValue</span><span class="hl opt">(</span><span class="hl kwb">const</span> ControlValue <span class="hl opt">&</span>other<span class="hl opt">)</span> <span class="hl opt">:</span> <span class="hl kwd">type_</span><span class="hl opt">(</span>ControlTypeNone<span class="hl opt">),</span> <span class="hl kwd">numElements_</span><span class="hl opt">(</span><span class="hl num">0</span><span class="hl opt">)</span> <span class="hl opt">{</span> <span class="hl opt">*</span><span class="hl kwa">this</span> <span class="hl opt">=</span> other<span class="hl opt">;</span> <span class="hl opt">}</span> <span class="hl com">/**</span> <span class="hl com"> * \brief Replace the content of the ControlValue with a copy of the content</span> <span class="hl com"> * of \a other</span> <span class="hl com"> * \param[in] other The ControlValue to copy content from</span> <span class="hl com"> * \return The ControlValue with its content replaced with the one of \a other</span> <span class="hl com"> */</span> ControlValue <span class="hl opt">&</span><span class="hl kwc">ControlValue</span><span class="hl opt">::</span><span class="hl kwc">operator</span><span class="hl opt">=(</span><span class="hl kwb">const</span> ControlValue <span class="hl opt">&</span>other<span class="hl opt">)</span> <span class="hl opt">{</span> <span class="hl kwd">set</span><span class="hl opt">(</span>other<span class="hl opt">.</span>type_<span class="hl opt">,</span> other<span class="hl opt">.</span>isArray_<span class="hl opt">,</span> other<span class="hl opt">.</span><span class="hl kwd">data</span><span class="hl opt">().</span><span class="hl kwd">data</span><span class="hl opt">(),</span> other<span class="hl opt">.</span>numElements_<span class="hl opt">,</span> ControlValueSize<span class="hl opt">[</span>other<span class="hl opt">.</span>type_<span class="hl opt">]);</span> <span class="hl kwa">return</span> <span class="hl opt">*</span><span class="hl kwa">this</span><span class="hl opt">;</span> <span class="hl opt">}</span> <span class="hl com">/**</span> <span class="hl com"> * \fn ControlValue::type()</span> <span class="hl com"> * \brief Retrieve the data type of the value</span> <span class="hl com"> * \return The value data type</span> <span class="hl com"> */</span> <span class="hl com">/**</span> <span class="hl com"> * \fn ControlValue::isNone()</span> <span class="hl com"> * \brief Determine if the value is not initialised</span> <span class="hl com"> * \return True if the value type is ControlTypeNone, false otherwise</span> <span class="hl com"> */</span> <span class="hl com">/**</span> <span class="hl com"> * \fn ControlValue::isArray()</span> <span class="hl com"> * \brief Determine if the value stores an array</span> <span class="hl com"> * \return True if the value stores an array, false otherwise</span> <span class="hl com"> */</span> <span class="hl com">/**</span> <span class="hl com"> * \fn ControlValue::numElements()</span> <span class="hl com"> * \brief Retrieve the number of elements stored in the ControlValue</span> <span class="hl com"> *</span> <span class="hl com"> * For instances storing an array, this function returns the number of elements</span> <span class="hl com"> * in the array. For instances storing a string, it returns the length of the</span> <span class="hl com"> * string, not counting the terminating '\0'. Otherwise, it returns 1.</span> <span class="hl com"> *</span> <span class="hl com"> * \return The number of elements stored in the ControlValue</span> <span class="hl com"> */</span> <span class="hl com">/**</span> <span class="hl com"> * \brief Retrieve the raw data of a control value</span> <span class="hl com"> * \return The raw data of the control value as a span of uint8_t</span> <span class="hl com"> */</span> Span<span class="hl opt"><</span><span class="hl kwb">const uint8_t</span><span class="hl opt">></span> <span class="hl kwc">ControlValue</span><span class="hl opt">::</span><span class="hl kwd">data</span><span class="hl opt">()</span> <span class="hl kwb">const</span> <span class="hl opt">{</span> <span class="hl kwc">std</span><span class="hl opt">::</span><span class="hl kwb">size_t</span> size <span class="hl opt">=</span> numElements_ <span class="hl opt">*</span> ControlValueSize<span class="hl opt">[</span>type_<span class="hl opt">];</span> <span class="hl kwb">const uint8_t</span> <span class="hl opt">*</span>data <span class="hl opt">=</span> size <span class="hl opt">></span> <span class="hl kwa">sizeof</span><span class="hl opt">(</span>value_<span class="hl opt">)</span> <span class="hl opt">?</span> <span class="hl kwa">reinterpret_cast</span><span class="hl opt"><</span><span class="hl kwb">const uint8_t</span> <span class="hl opt">*>(</span>storage_<span class="hl opt">)</span> <span class="hl opt">:</span> <span class="hl kwa">reinterpret_cast</span><span class="hl opt"><</span><span class="hl kwb">const uint8_t</span> <span class="hl opt">*>(&</span>value_<span class="hl opt">);</span> <span class="hl kwa">return</span> <span class="hl opt">{</span> data<span class="hl opt">,</span> size <span class="hl opt">};</span> <span class="hl opt">}</span> <span class="hl com">/**</span> <span class="hl com"> * \copydoc ControlValue::data() const</span> <span class="hl com"> */</span> Span<span class="hl opt"><</span><span class="hl kwb">uint8_t</span><span class="hl opt">></span> <span class="hl kwc">ControlValue</span><span class="hl opt">::</span><span class="hl kwd">data</span><span class="hl opt">()</span> <span class="hl opt">{</span> Span<span class="hl opt"><</span><span class="hl kwb">const uint8_t</span><span class="hl opt">></span> data <span class="hl opt">=</span> <span class="hl kwa">const_cast</span><span class="hl opt"><</span><span class="hl kwb">const</span> ControlValue <span class="hl opt">*>(</span><span class="hl kwa">this</span><span class="hl opt">)-></span><span class="hl kwd">data</span><span class="hl opt">();</span> <span class="hl kwa">return</span> <span class="hl opt">{</span> <span class="hl kwa">const_cast</span><span class="hl opt"><</span><span class="hl kwb">uint8_t</span> <span class="hl opt">*>(</span>data<span class="hl opt">.</span><span class="hl kwd">data</span><span class="hl opt">()),</span> data<span class="hl opt">.</span><span class="hl kwd">size</span><span class="hl opt">() };</span> <span class="hl opt">}</span> <span class="hl com">/**</span> <span class="hl com"> * \brief Assemble and return a string describing the value</span> <span class="hl com"> * \return A string describing the ControlValue</span> <span class="hl com"> */</span> <span class="hl kwc">std</span><span class="hl opt">::</span>string <span class="hl kwc">ControlValue</span><span class="hl opt">::</span><span class="hl kwd">toString</span><span class="hl opt">()</span> <span class="hl kwb">const</span> <span class="hl opt">{</span> <span class="hl kwa">if</span> <span class="hl opt">(</span>type_ <span class="hl opt">==</span> ControlTypeNone<span class="hl opt">)</span> <span class="hl kwa">return</span> <span class="hl str">"<ValueType Error>"</span><span class="hl opt">;</span> <span class="hl kwb">const uint8_t</span> <span class="hl opt">*</span>data <span class="hl opt">=</span> <span class="hl kwc">ControlValue</span><span class="hl opt">::</span><span class="hl kwd">data</span><span class="hl opt">().</span><span class="hl kwd">data</span><span class="hl opt">();</span> <span class="hl kwa">if</span> <span class="hl opt">(</span>type_ <span class="hl opt">==</span> ControlTypeString<span class="hl opt">)</span> <span class="hl kwa">return</span> <span class="hl kwc">std</span><span class="hl opt">::</span><span class="hl kwd">string</span><span class="hl opt">(</span><span class="hl kwa">reinterpret_cast</span><span class="hl opt"><</span><span class="hl kwb">const char</span> <span class="hl opt">*>(</span>data<span class="hl opt">),</span> numElements_<span class="hl opt">);</span> <span class="hl kwc">std</span><span class="hl opt">::</span>string <span class="hl kwd">str</span><span class="hl opt">(</span>isArray_ <span class="hl opt">?</span> <span class="hl str">"[ "</span> <span class="hl opt">:</span> <span class="hl str">""</span><span class="hl opt">);</span> <span class="hl kwa">for</span> <span class="hl opt">(</span><span class="hl kwb">unsigned int</span> i <span class="hl opt">=</span> <span class="hl num">0</span><span class="hl opt">;</span> i <span class="hl opt"><</span> numElements_<span class="hl opt">; ++</span>i<span class="hl opt">) {</span> <span class="hl kwa">switch</span> <span class="hl opt">(</span>type_<span class="hl opt">) {</span> <span class="hl kwa">case</span> ControlTypeBool<span class="hl opt">: {</span> <span class="hl kwb">const bool</span> <span class="hl opt">*</span>value <span class="hl opt">=</span> <span class="hl kwa">reinterpret_cast</span><span class="hl opt"><</span><span class="hl kwb">const bool</span> <span class="hl opt">*>(</span>data<span class="hl opt">);</span> str <span class="hl opt">+= *</span>value <span class="hl opt">?</span> <span class="hl str">"true"</span> <span class="hl opt">:</span> <span class="hl str">"false"</span><span class="hl opt">;</span> <span class="hl kwa">break</span><span class="hl opt">;</span> <span class="hl opt">}</span> <span class="hl kwa">case</span> ControlTypeByte<span class="hl opt">: {</span> <span class="hl kwb">const uint8_t</span> <span class="hl opt">*</span>value <span class="hl opt">=</span> <span class="hl kwa">reinterpret_cast</span><span class="hl opt"><</span><span class="hl kwb">const uint8_t</span> <span class="hl opt">*>(</span>data<span class="hl opt">);</span> str <span class="hl opt">+=</span> <span class="hl kwc">std</span><span class="hl opt">::</span><span class="hl kwd">to_string</span><span class="hl opt">(*</span>value<span class="hl opt">);</span> <span class="hl kwa">break</span><span class="hl opt">;</span> <span class="hl opt">}</span> <span class="hl kwa">case</span> ControlTypeInteger32<span class="hl opt">: {</span> <span class="hl kwb">const int32_t</span> <span class="hl opt">*</span>value <span class="hl opt">=</span> <span class="hl kwa">reinterpret_cast</span><span class="hl opt"><</span><span class="hl kwb">const int32_t</span> <span class="hl opt">*>(</span>data<span class="hl opt">);</span> str <span class="hl opt">+=</span> <span class="hl kwc">std</span><span class="hl opt">::</span><span class="hl kwd">to_string</span><span class="hl opt">(*</span>value<span class="hl opt">);</span> <span class="hl kwa">break</span><span class="hl opt">;</span> <span class="hl opt">}</span> <span class="hl kwa">case</span> ControlTypeInteger64<span class="hl opt">: {</span> <span class="hl kwb">const int64_t</span> <span class="hl opt">*</span>value <span class="hl opt">=</span> <span class="hl kwa">reinterpret_cast</span><span class="hl opt"><</span><span class="hl kwb">const int64_t</span> <span class="hl opt">*>(</span>data<span class="hl opt">);</span> str <span class="hl opt">+=</span> <span class="hl kwc">std</span><span class="hl opt">::</span><span class="hl kwd">to_string</span><span class="hl opt">(*</span>value<span class="hl opt">);</span> <span class="hl kwa">break</span><span class="hl opt">;</span> <span class="hl opt">}</span> <span class="hl kwa">case</span> ControlTypeFloat<span class="hl opt">: {</span> <span class="hl kwb">const float</span> <span class="hl opt">*</span>value <span class="hl opt">=</span> <span class="hl kwa">reinterpret_cast</span><span class="hl opt"><</span><span class="hl kwb">const float</span> <span class="hl opt">*>(</span>data<span class="hl opt">);</span> str <span class="hl opt">+=</span> <span class="hl kwc">std</span><span class="hl opt">::</span><span class="hl kwd">to_string</span><span class="hl opt">(*</span>value<span class="hl opt">);</span> <span class="hl kwa">break</span><span class="hl opt">;</span> <span class="hl opt">}</span> <span class="hl kwa">case</span> ControlTypeRectangle<span class="hl opt">: {</span> <span class="hl kwb">const</span> Rectangle <span class="hl opt">*</span>value <span class="hl opt">=</span> <span class="hl kwa">reinterpret_cast</span><span class="hl opt"><</span><span class="hl kwb">const</span> Rectangle <span class="hl opt">*>(</span>data<span class="hl opt">);</span> str <span class="hl opt">+=</span> value<span class="hl opt">-></span><span class="hl kwd">toString</span><span class="hl opt">();</span> <span class="hl kwa">break</span><span class="hl opt">;</span> <span class="hl opt">}</span> <span class="hl kwa">case</span> ControlTypeSize<span class="hl opt">: {</span> <span class="hl kwb">const</span> Size <span class="hl opt">*</span>value <span class="hl opt">=</span> <span class="hl kwa">reinterpret_cast</span><span class="hl opt"><</span><span class="hl kwb">const</span> Size <span class="hl opt">*>(</span>data<span class="hl opt">);</span> str <span class="hl opt">+=</span> value<span class="hl opt">-></span><span class="hl kwd">toString</span><span class="hl opt">();</span> <span class="hl kwa">break</span><span class="hl opt">;</span> <span class="hl opt">}</span> <span class="hl kwa">case</span> ControlTypeNone<span class="hl opt">:</span> <span class="hl kwa">case</span> ControlTypeString<span class="hl opt">:</span> <span class="hl kwa">break</span><span class="hl opt">;</span> <span class="hl opt">}</span> <span class="hl kwa">if</span> <span class="hl opt">(</span>i <span class="hl opt">+</span> <span class="hl num">1</span> <span class="hl opt">!=</span> numElements_<span class="hl opt">)</span> str <span class="hl opt">+=</span> <span class="hl str">", "</span><span class="hl opt">;</span> data <span class="hl opt">+=</span> ControlValueSize<span class="hl opt">[</span>type_<span class="hl opt">];</span> <span class="hl opt">}</span> <span class="hl kwa">if</span> <span class="hl opt">(</span>isArray_<span class="hl opt">)</span> str <span class="hl opt">+=</span> <span class="hl str">" ]"</span><span class="hl opt">;</span> <span class="hl kwa">return</span> str<span class="hl opt">;</span> <span class="hl opt">}</span> <span class="hl com">/**</span> <span class="hl com"> * \brief Compare ControlValue instances for equality</span> <span class="hl com"> * \return True if the values have identical types and values, false otherwise</span> <span class="hl com"> */</span> <span class="hl kwb">bool</span> <span class="hl kwc">ControlValue</span><span class="hl opt">::</span><span class="hl kwc">operator</span><span class="hl opt">==(</span><span class="hl kwb">const</span> ControlValue <span class="hl opt">&</span>other<span class="hl opt">)</span> <span class="hl kwb">const</span> <span class="hl opt">{</span> <span class="hl kwa">if</span> <span class="hl opt">(</span>type_ <span class="hl opt">!=</span> other<span class="hl opt">.</span>type_<span class="hl opt">)</span> <span class="hl kwa">return false</span><span class="hl opt">;</span> <span class="hl kwa">if</span> <span class="hl opt">(</span>numElements_ <span class="hl opt">!=</span> other<span class="hl opt">.</span><span class="hl kwd">numElements</span><span class="hl opt">())</span> <span class="hl kwa">return false</span><span class="hl opt">;</span> <span class="hl kwa">if</span> <span class="hl opt">(</span>isArray_ <span class="hl opt">!=</span> other<span class="hl opt">.</span>isArray_<span class="hl opt">)</span> <span class="hl kwa">return false</span><span class="hl opt">;</span> <span class="hl kwa">return</span> <span class="hl kwd">memcmp</span><span class="hl opt">(</span><span class="hl kwd">data</span><span class="hl opt">().</span><span class="hl kwd">data</span><span class="hl opt">(),</span> other<span class="hl opt">.</span><span class="hl kwd">data</span><span class="hl opt">().</span><span class="hl kwd">data</span><span class="hl opt">(),</span> <span class="hl kwd">data</span><span class="hl opt">().</span><span class="hl kwd">size</span><span class="hl opt">()) ==</span> <span class="hl num">0</span><span class="hl opt">;</span> <span class="hl opt">}</span> <span class="hl com">/**</span> <span class="hl com"> * \fn bool ControlValue::operator!=()</span> <span class="hl com"> * \brief Compare ControlValue instances for non equality</span> <span class="hl com"> * \return False if the values have identical types and values, true otherwise</span> <span class="hl com"> */</span> <span class="hl com">/**</span> <span class="hl com"> * \fn template<typename T> T ControlValue::get() const</span> <span class="hl com"> * \brief Get the control value</span> <span class="hl com"> *</span> <span class="hl com"> * This function returns the contained value as an instance of \a T. If the</span> <span class="hl com"> * ControlValue instance stores a single value, the type \a T shall match the</span> <span class="hl com"> * stored value type(). If the instance stores an array of values, the type</span> <span class="hl com"> * \a T should be equal to Span<const R>, and the type \a R shall match the</span> <span class="hl com"> * stored value type(). The behaviour is undefined otherwise.</span> <span class="hl com"> *</span> <span class="hl com"> * Note that a ControlValue instance that stores a non-array value is not</span> <span class="hl com"> * equivalent to an instance that stores an array value containing a single</span> <span class="hl com"> * element. The latter shall be accessed through a Span<const R> type, while</span> <span class="hl com"> * the former shall be accessed through a type \a T corresponding to type().</span> <span class="hl com"> *</span> <span class="hl com"> * \return The control value</span> <span class="hl com"> */</span> <span class="hl com">/**</span> <span class="hl com"> * \fn template<typename T> void ControlValue::set(const T &value)</span> <span class="hl com"> * \brief Set the control value to \a value</span> <span class="hl com"> * \param[in] value The control value</span> <span class="hl com"> *</span> <span class="hl com"> * This function stores the \a value in the instance. If the type \a T is</span> <span class="hl com"> * equivalent to Span<R>, the instance stores an array of values of type \a R.</span> <span class="hl com"> * Otherwise the instance stores a single value of type \a T. The numElements()</span> <span class="hl com"> * and type() are updated to reflect the stored value.</span> <span class="hl com"> *</span> <span class="hl com"> * The entire content of \a value is copied to the instance, no reference to \a</span> <span class="hl com"> * value or to the data it references is retained. This may be an expensive</span> <span class="hl com"> * operation for Span<> values that refer to large arrays.</span> <span class="hl com"> */</span> <span class="hl kwb">void</span> <span class="hl kwc">ControlValue</span><span class="hl opt">::</span><span class="hl kwd">set</span><span class="hl opt">(</span>ControlType type<span class="hl opt">,</span> <span class="hl kwb">bool</span> isArray<span class="hl opt">,</span> <span class="hl kwb">const void</span> <span class="hl opt">*</span>data<span class="hl opt">,</span> <span class="hl kwc">std</span><span class="hl opt">::</span><span class="hl kwb">size_t</span> numElements<span class="hl opt">,</span> <span class="hl kwc">std</span><span class="hl opt">::</span><span class="hl kwb">size_t</span> elementSize<span class="hl opt">)</span> <span class="hl opt">{</span> <span class="hl kwd">ASSERT</span><span class="hl opt">(</span>elementSize <span class="hl opt">==</span> ControlValueSize<span class="hl opt">[</span>type<span class="hl opt">]);</span> <span class="hl kwd">reserve</span><span class="hl opt">(</span>type<span class="hl opt">,</span> isArray<span class="hl opt">,</span> numElements<span class="hl opt">);</span> Span<span class="hl opt"><</span><span class="hl kwb">uint8_t</span><span class="hl opt">></span> storage <span class="hl opt">=</span> <span class="hl kwc">ControlValue</span><span class="hl opt">::</span><span class="hl kwd">data</span><span class="hl opt">();</span> <span class="hl kwd">memcpy</span><span class="hl opt">(</span>storage<span class="hl opt">.</span><span class="hl kwd">data</span><span class="hl opt">(),</span> data<span class="hl opt">,</span> storage<span class="hl opt">.</span><span class="hl kwd">size</span><span class="hl opt">());</span> <span class="hl opt">}</span> <span class="hl com">/**</span> <span class="hl com"> * \brief Set the control type and reserve memory</span> <span class="hl com"> * \param[in] type The control type</span> <span class="hl com"> * \param[in] isArray True to make the value an array</span> <span class="hl com"> * \param[in] numElements The number of elements</span> <span class="hl com"> *</span> <span class="hl com"> * This function sets the type of the control value to \a type, and reserves</span> <span class="hl com"> * memory to store the control value. If \a isArray is true, the instance</span> <span class="hl com"> * becomes an array control and storage for \a numElements is reserved.</span> <span class="hl com"> * Otherwise the instance becomes a simple control, numElements is ignored, and</span> <span class="hl com"> * storage for the single element is reserved.</span> <span class="hl com"> */</span> <span class="hl kwb">void</span> <span class="hl kwc">ControlValue</span><span class="hl opt">::</span><span class="hl kwd">reserve</span><span class="hl opt">(</span>ControlType type<span class="hl opt">,</span> <span class="hl kwb">bool</span> isArray<span class="hl opt">,</span> <span class="hl kwc">std</span><span class="hl opt">::</span><span class="hl kwb">size_t</span> numElements<span class="hl opt">)</span> <span class="hl opt">{</span> <span class="hl kwa">if</span> <span class="hl opt">(!</span>isArray<span class="hl opt">)</span> numElements <span class="hl opt">=</span> <span class="hl num">1</span><span class="hl opt">;</span> <span class="hl kwc">std</span><span class="hl opt">::</span><span class="hl kwb">size_t</span> oldSize <span class="hl opt">=</span> numElements_ <span class="hl opt">*</span> ControlValueSize<span class="hl opt">[</span>type_<span class="hl opt">];</span> <span class="hl kwc">std</span><span class="hl opt">::</span><span class="hl kwb">size_t</span> newSize <span class="hl opt">=</span> numElements <span class="hl opt">*</span> ControlValueSize<span class="hl opt">[</span>type<span class="hl opt">];</span> <span class="hl kwa">if</span> <span class="hl opt">(</span>oldSize <span class="hl opt">!=</span> newSize<span class="hl opt">)</span> <span class="hl kwd">release</span><span class="hl opt">();</span> type_ <span class="hl opt">=</span> type<span class="hl opt">;</span> isArray_ <span class="hl opt">=</span> isArray<span class="hl opt">;</span> numElements_ <span class="hl opt">=</span> numElements<span class="hl opt">;</span> <span class="hl kwa">if</span> <span class="hl opt">(</span>oldSize <span class="hl opt">==</span> newSize<span class="hl opt">)</span> <span class="hl kwa">return</span><span class="hl opt">;</span> <span class="hl kwa">if</span> <span class="hl opt">(</span>newSize <span class="hl opt">></span> <span class="hl kwa">sizeof</span><span class="hl opt">(</span>value_<span class="hl opt">))</span> storage_ <span class="hl opt">=</span> <span class="hl kwa">reinterpret_cast</span><span class="hl opt"><</span><span class="hl kwb">void</span> <span class="hl opt">*>(</span><span class="hl kwa">new</span> <span class="hl kwb">uint8_t</span><span class="hl opt">[</span>newSize<span class="hl opt">]);</span> <span class="hl opt">}</span> <span class="hl com">/**</span> <span class="hl com"> * \class ControlId</span> <span class="hl com"> * \brief Control static metadata</span> <span class="hl com"> *</span> <span class="hl com"> * The ControlId class stores a control ID, name and data type. It provides</span> <span class="hl com"> * unique identification of a control, but without support for compile-time</span> <span class="hl com"> * type deduction that the derived template Control class supports. See the</span> <span class="hl com"> * Control class for more information.</span> <span class="hl com"> */</span> <span class="hl com">/**</span> <span class="hl com"> * \fn ControlId::ControlId(unsigned int id, const std::string &name, ControlType type)</span> <span class="hl com"> * \brief Construct a ControlId instance</span> <span class="hl com"> * \param[in] id The control numerical ID</span> <span class="hl com"> * \param[in] name The control name</span> <span class="hl com"> * \param[in] type The control data type</span> <span class="hl com"> */</span> <span class="hl com">/**</span> <span class="hl com"> * \fn unsigned int ControlId::id() const</span> <span class="hl com"> * \brief Retrieve the control numerical ID</span> <span class="hl com"> * \return The control numerical ID</span> <span class="hl com"> */</span> <span class="hl com">/**</span> <span class="hl com"> * \fn const char *ControlId::name() const</span> <span class="hl com"> * \brief Retrieve the control name</span> <span class="hl com"> * \return The control name</span> <span class="hl com"> */</span> <span class="hl com">/**</span> <span class="hl com"> * \fn ControlType ControlId::type() const</span> <span class="hl com"> * \brief Retrieve the control data type</span> <span class="hl com"> * \return The control data type</span> <span class="hl com"> */</span> <span class="hl com">/**</span> <span class="hl com"> * \fn bool operator==(unsigned int lhs, const ControlId &rhs)</span> <span class="hl com"> * \brief Compare a ControlId with a control numerical ID</span> <span class="hl com"> * \param[in] lhs Left-hand side numerical ID</span> <span class="hl com"> * \param[in] rhs Right-hand side ControlId</span> <span class="hl com"> *</span> <span class="hl com"> * \return True if \a lhs is equal to \a rhs.id(), false otherwise</span> <span class="hl com"> */</span> <span class="hl com">/**</span> <span class="hl com"> * \fn bool operator==(const ControlId &lhs, unsigned int rhs)</span> <span class="hl com"> * \brief Compare a ControlId with a control numerical ID</span> <span class="hl com"> * \param[in] lhs Left-hand side ControlId</span> <span class="hl com"> * \param[in] rhs Right-hand side numerical ID</span> <span class="hl com"> *</span> <span class="hl com"> * \return True if \a lhs.id() is equal to \a rhs, false otherwise</span> <span class="hl com"> */</span> <span class="hl com">/**</span> <span class="hl com"> * \class Control</span> <span class="hl com"> * \brief Describe a control and its intrinsic properties</span> <span class="hl com"> *</span> <span class="hl com"> * The Control class models a control exposed by an object. Its template type</span> <span class="hl com"> * name T refers to the control data type, and allows functions that operate on</span> <span class="hl com"> * control values to be defined as template functions using the same type T for</span> <span class="hl com"> * the control value. See for instance how the ControlList::get() function</span> <span class="hl com"> * returns a value corresponding to the type of the requested control.</span> <span class="hl com"> *</span> <span class="hl com"> * While this class is the main means to refer to a control, the control</span> <span class="hl com"> * identifying information is stored in the non-template base ControlId class.</span> <span class="hl com"> * This allows code that operates on a set of controls of different types to</span> <span class="hl com"> * reference those controls through a ControlId instead of a Control. For</span> <span class="hl com"> * instance, the list of controls supported by a camera is exposed as ControlId</span> <span class="hl com"> * instead of Control.</span> <span class="hl com"> *</span> <span class="hl com"> * Controls of any type can be defined through template specialisation, but</span> <span class="hl com"> * libcamera only supports the bool, uint8_t, int32_t, int64_t and float types</span> <span class="hl com"> * natively (this includes types that are equivalent to the supported types,</span> <span class="hl com"> * such as int and long int).</span> <span class="hl com"> *</span> <span class="hl com"> * Controls IDs shall be unique. While nothing prevents multiple instances of</span> <span class="hl com"> * the Control class to be created with the same ID for the same object, doing</span> <span class="hl com"> * so may cause undefined behaviour.</span> <span class="hl com"> */</span> <span class="hl com">/**</span> <span class="hl com"> * \fn Control::Control(unsigned int id, const char *name)</span> <span class="hl com"> * \brief Construct a Control instance</span> <span class="hl com"> * \param[in] id The control numerical ID</span> <span class="hl com"> * \param[in] name The control name</span> <span class="hl com"> *</span> <span class="hl com"> * The control data type is automatically deduced from the template type T.</span> <span class="hl com"> */</span> <span class="hl com">/**</span> <span class="hl com"> * \typedef Control::type</span> <span class="hl com"> * \brief The Control template type T</span> <span class="hl com"> */</span> <span class="hl com">/**</span> <span class="hl com"> * \class ControlInfo</span> <span class="hl com"> * \brief Describe the limits of valid values for a Control</span> <span class="hl com"> *</span> <span class="hl com"> * The ControlInfo expresses the constraints on valid values for a control.</span> <span class="hl com"> * The constraints depend on the object the control applies to, and are</span> <span class="hl com"> * constant for the lifetime of that object. They are typically constructed by</span> <span class="hl com"> * pipeline handlers to describe the controls they support.</span> <span class="hl com"> */</span> <span class="hl com">/**</span> <span class="hl com"> * \brief Construct a ControlInfo with minimum and maximum range parameters</span> <span class="hl com"> * \param[in] min The control minimum value</span> <span class="hl com"> * \param[in] max The control maximum value</span> <span class="hl com"> * \param[in] def The control default value</span> <span class="hl com"> */</span> <span class="hl kwc">ControlInfo</span><span class="hl opt">::</span><span class="hl kwd">ControlInfo</span><span class="hl opt">(</span><span class="hl kwb">const</span> ControlValue <span class="hl opt">&</span>min<span class="hl opt">,</span> <span class="hl kwb">const</span> ControlValue <span class="hl opt">&</span>max<span class="hl opt">,</span> <span class="hl kwb">const</span> ControlValue <span class="hl opt">&</span>def<span class="hl opt">)</span> <span class="hl opt">:</span> <span class="hl kwd">min_</span><span class="hl opt">(</span>min<span class="hl opt">),</span> <span class="hl kwd">max_</span><span class="hl opt">(</span>max<span class="hl opt">),</span> <span class="hl kwd">def_</span><span class="hl opt">(</span>def<span class="hl opt">)</span> <span class="hl opt">{</span> <span class="hl opt">}</span> <span class="hl com">/**</span> <span class="hl com"> * \brief Construct a ControlInfo from the list of valid values</span> <span class="hl com"> * \param[in] values The control valid values</span> <span class="hl com"> * \param[in] def The control default value</span> <span class="hl com"> *</span> <span class="hl com"> * Construct a ControlInfo from a list of valid values. The ControlInfo</span> <span class="hl com"> * minimum and maximum values are set to the first and last members of the</span> <span class="hl com"> * values list respectively. The default value is set to \a def if provided, or</span> <span class="hl com"> * to the minimum value otherwise.</span> <span class="hl com"> */</span> <span class="hl kwc">ControlInfo</span><span class="hl opt">::</span><span class="hl kwd">ControlInfo</span><span class="hl opt">(</span>Span<span class="hl opt"><</span><span class="hl kwb">const</span> ControlValue<span class="hl opt">></span> values<span class="hl opt">,</span> <span class="hl kwb">const</span> ControlValue <span class="hl opt">&</span>def<span class="hl opt">)</span> <span class="hl opt">{</span> min_ <span class="hl opt">=</span> values<span class="hl opt">.</span><span class="hl kwd">front</span><span class="hl opt">();</span> max_ <span class="hl opt">=</span> values<span class="hl opt">.</span><span class="hl kwd">back</span><span class="hl opt">();</span> def_ <span class="hl opt">= !</span>def<span class="hl opt">.</span><span class="hl kwd">isNone</span><span class="hl opt">() ?</span> def <span class="hl opt">:</span> values<span class="hl opt">.</span><span class="hl kwd">front</span><span class="hl opt">();</span> values_<span class="hl opt">.</span><span class="hl kwd">reserve</span><span class="hl opt">(</span>values<span class="hl opt">.</span><span class="hl kwd">size</span><span class="hl opt">());</span> <span class="hl kwa">for</span> <span class="hl opt">(</span><span class="hl kwb">const</span> ControlValue <span class="hl opt">&</span>value <span class="hl opt">:</span> values<span class="hl opt">)</span> values_<span class="hl opt">.</span><span class="hl kwd">push_back</span><span class="hl opt">(</span>value<span class="hl opt">);</span> <span class="hl opt">}</span> <span class="hl com">/**</span> <span class="hl com"> * \brief Construct a boolean ControlInfo with both boolean values</span> <span class="hl com"> * \param[in] values The control valid boolean values (both true and false)</span> <span class="hl com"> * \param[in] def The control default boolean value</span> <span class="hl com"> *</span> <span class="hl com"> * Construct a ControlInfo for a boolean control, where both true and false are</span> <span class="hl com"> * valid values. \a values must be { false, true } (the order is irrelevant).</span> <span class="hl com"> * The minimum value will always be false, and the maximum always true. The</span> <span class="hl com"> * default value is \a def.</span> <span class="hl com"> */</span> <span class="hl kwc">ControlInfo</span><span class="hl opt">::</span><span class="hl kwd">ControlInfo</span><span class="hl opt">(</span><span class="hl kwc">std</span><span class="hl opt">::</span>set<span class="hl opt"><</span><span class="hl kwb">bool</span><span class="hl opt">></span> values<span class="hl opt">,</span> <span class="hl kwb">bool</span> def<span class="hl opt">)</span> <span class="hl opt">:</span> <span class="hl kwd">min_</span><span class="hl opt">(</span><span class="hl kwa">false</span><span class="hl opt">),</span> <span class="hl kwd">max_</span><span class="hl opt">(</span><span class="hl kwa">true</span><span class="hl opt">),</span> <span class="hl kwd">def_</span><span class="hl opt">(</span>def<span class="hl opt">),</span> <span class="hl kwd">values_</span><span class="hl opt">({</span> <span class="hl kwa">false</span><span class="hl opt">,</span> <span class="hl kwa">true</span> <span class="hl opt">})</span> <span class="hl opt">{</span> <span class="hl kwd">ASSERT</span><span class="hl opt">(</span>values<span class="hl opt">.</span><span class="hl kwd">count</span><span class="hl opt">(</span>def<span class="hl opt">) &&</span> values<span class="hl opt">.</span><span class="hl kwd">size</span><span class="hl opt">() ==</span> <span class="hl num">2</span><span class="hl opt">);</span> <span class="hl opt">}</span> <span class="hl com">/**</span> <span class="hl com"> * \brief Construct a boolean ControlInfo with only one valid value</span> <span class="hl com"> * \param[in] value The control valid boolean value</span> <span class="hl com"> *</span> <span class="hl com"> * Construct a ControlInfo for a boolean control, where there is only valid</span> <span class="hl com"> * value. The minimum, maximum, and default values will all be \a value.</span> <span class="hl com"> */</span> <span class="hl kwc">ControlInfo</span><span class="hl opt">::</span><span class="hl kwd">ControlInfo</span><span class="hl opt">(</span><span class="hl kwb">bool</span> value<span class="hl opt">)</span> <span class="hl opt">:</span> <span class="hl kwd">min_</span><span class="hl opt">(</span>value<span class="hl opt">),</span> <span class="hl kwd">max_</span><span class="hl opt">(</span>value<span class="hl opt">),</span> <span class="hl kwd">def_</span><span class="hl opt">(</span>value<span class="hl opt">)</span> <span class="hl opt">{</span> values_ <span class="hl opt">= {</span> value <span class="hl opt">};</span> <span class="hl opt">}</span> <span class="hl com">/**</span> <span class="hl com"> * \fn ControlInfo::min()</span> <span class="hl com"> * \brief Retrieve the minimum value of the control</span> <span class="hl com"> *</span> <span class="hl com"> * For string controls, this is the minimum length of the string, not counting</span> <span class="hl com"> * the terminating '\0'. For all other control types, this is the minimum value</span> <span class="hl com"> * of each element.</span> <span class="hl com"> *</span> <span class="hl com"> * \return A ControlValue with the minimum value for the control</span> <span class="hl com"> */</span> <span class="hl com">/**</span> <span class="hl com"> * \fn ControlInfo::max()</span> <span class="hl com"> * \brief Retrieve the maximum value of the control</span> <span class="hl com"> *</span> <span class="hl com"> * For string controls, this is the maximum length of the string, not counting</span> <span class="hl com"> * the terminating '\0'. For all other control types, this is the maximum value</span> <span class="hl com"> * of each element.</span> <span class="hl com"> *</span> <span class="hl com"> * \return A ControlValue with the maximum value for the control</span> <span class="hl com"> */</span> <span class="hl com">/**</span> <span class="hl com"> * \fn ControlInfo::def()</span> <span class="hl com"> * \brief Retrieve the default value of the control</span> <span class="hl com"> * \return A ControlValue with the default value for the control</span> <span class="hl com"> */</span> <span class="hl com">/**</span> <span class="hl com"> * \fn ControlInfo::values()</span> <span class="hl com"> * \brief Retrieve the list of valid values</span> <span class="hl com"> *</span> <span class="hl com"> * For controls that support a pre-defined number of values, the enumeration of</span> <span class="hl com"> * those is reported through a vector of ControlValue instances accessible with</span> <span class="hl com"> * this function.</span> <span class="hl com"> *</span> <span class="hl com"> * \return A vector of ControlValue representing the control valid values</span> <span class="hl com"> */</span> <span class="hl com">/**</span> <span class="hl com"> * \brief Provide a string representation of the ControlInfo</span> <span class="hl com"> */</span> <span class="hl kwc">std</span><span class="hl opt">::</span>string <span class="hl kwc">ControlInfo</span><span class="hl opt">::</span><span class="hl kwd">toString</span><span class="hl opt">()</span> <span class="hl kwb">const</span> <span class="hl opt">{</span> <span class="hl kwc">std</span><span class="hl opt">::</span>stringstream ss<span class="hl opt">;</span> ss <span class="hl opt"><<</span> <span class="hl str">"["</span> <span class="hl opt"><<</span> min_<span class="hl opt">.</span><span class="hl kwd">toString</span><span class="hl opt">() <<</span> <span class="hl str">".."</span> <span class="hl opt"><<</span> max_<span class="hl opt">.</span><span class="hl kwd">toString</span><span class="hl opt">() <<</span> <span class="hl str">"]"</span><span class="hl opt">;</span> <span class="hl kwa">return</span> ss<span class="hl opt">.</span><span class="hl kwd">str</span><span class="hl opt">();</span> <span class="hl opt">}</span> <span class="hl com">/**</span> <span class="hl com"> * \fn bool ControlInfo::operator==()</span> <span class="hl com"> * \brief Compare ControlInfo instances for equality</span> <span class="hl com"> * \return True if the constraints have identical min and max, false otherwise</span> <span class="hl com"> */</span> <span class="hl com">/**</span> <span class="hl com"> * \fn bool ControlInfo::operator!=()</span> <span class="hl com"> * \brief Compare ControlInfo instances for non equality</span> <span class="hl com"> * \return True if the constraints have different min and max, false otherwise</span> <span class="hl com"> */</span> <span class="hl com">/**</span> <span class="hl com"> * \typedef ControlIdMap</span> <span class="hl com"> * \brief A map of numerical control ID to ControlId</span> <span class="hl com"> *</span> <span class="hl com"> * The map is used by ControlList instances to access controls by numerical</span> <span class="hl com"> * IDs. A global map of all libcamera controls is provided by</span> <span class="hl com"> * controls::controls.</span> <span class="hl com"> */</span> <span class="hl com">/**</span> <span class="hl com"> * \class ControlInfoMap</span> <span class="hl com"> * \brief A map of ControlId to ControlInfo</span> <span class="hl com"> *</span> <span class="hl com"> * The ControlInfoMap class describes controls supported by an object as an</span> <span class="hl com"> * unsorted map of ControlId pointers to ControlInfo instances. Unlike the</span> <span class="hl com"> * standard std::unsorted_map<> class, it is designed to be immutable once</span> <span class="hl com"> * constructed, and thus only exposes the read accessors of the</span> <span class="hl com"> * std::unsorted_map<> base class.</span> <span class="hl com"> *</span> <span class="hl com"> * The class is constructed with a reference to a ControlIdMap. This allows</span> <span class="hl com"> * providing access to the mapped elements using numerical ID keys, in addition</span> <span class="hl com"> * to the features of the standard unsorted map. All ControlId keys in the map</span> <span class="hl com"> * must appear in the ControlIdMap.</span> <span class="hl com"> */</span> <span class="hl com">/**</span> <span class="hl com"> * \typedef ControlInfoMap::Map</span> <span class="hl com"> * \brief The base std::unsorted_map<> container</span> <span class="hl com"> */</span> <span class="hl com">/**</span> <span class="hl com"> * \fn ControlInfoMap::ControlInfoMap(const ControlInfoMap &other)</span> <span class="hl com"> * \brief Copy constructor, construct a ControlInfoMap from a copy of \a other</span> <span class="hl com"> * \param[in] other The other ControlInfoMap</span> <span class="hl com"> */</span> <span class="hl com">/**</span> <span class="hl com"> * \brief Construct a ControlInfoMap from an initializer list</span> <span class="hl com"> * \param[in] init The initializer list</span> <span class="hl com"> * \param[in] idmap The idmap used by the ControlInfoMap</span> <span class="hl com"> */</span> <span class="hl kwc">ControlInfoMap</span><span class="hl opt">::</span><span class="hl kwd">ControlInfoMap</span><span class="hl opt">(</span><span class="hl kwc">std</span><span class="hl opt">::</span>initializer_list<span class="hl opt"><</span><span class="hl kwc">Map</span><span class="hl opt">::</span>value_type<span class="hl opt">></span> init<span class="hl opt">,</span> <span class="hl kwb">const</span> ControlIdMap <span class="hl opt">&</span>idmap<span class="hl opt">)</span> <span class="hl opt">:</span> <span class="hl kwd">Map</span><span class="hl opt">(</span>init<span class="hl opt">),</span> <span class="hl kwd">idmap_</span><span class="hl opt">(&</span>idmap<span class="hl opt">)</span> <span class="hl opt">{</span> <span class="hl kwd">ASSERT</span><span class="hl opt">(</span><span class="hl kwd">validate</span><span class="hl opt">());</span> <span class="hl opt">}</span> <span class="hl com">/**</span> <span class="hl com"> * \brief Construct a ControlInfoMap from a plain map</span> <span class="hl com"> * \param[in] info The control info plain map</span> <span class="hl com"> * \param[in] idmap The idmap used by the ControlInfoMap</span> <span class="hl com"> *</span> <span class="hl com"> * Construct a new ControlInfoMap and populate its contents with those of</span> <span class="hl com"> * \a info using move semantics. Upon return the \a info map will be empty.</span> <span class="hl com"> */</span> <span class="hl kwc">ControlInfoMap</span><span class="hl opt">::</span><span class="hl kwd">ControlInfoMap</span><span class="hl opt">(</span>Map <span class="hl opt">&&</span>info<span class="hl opt">,</span> <span class="hl kwb">const</span> ControlIdMap <span class="hl opt">&</span>idmap<span class="hl opt">)</span> <span class="hl opt">:</span> <span class="hl kwd">Map</span><span class="hl opt">(</span><span class="hl kwc">std</span><span class="hl opt">::</span><span class="hl kwd">move</span><span class="hl opt">(</span>info<span class="hl opt">)),</span> <span class="hl kwd">idmap_</span><span class="hl opt">(&</span>idmap<span class="hl opt">)</span> <span class="hl opt">{</span> <span class="hl kwd">ASSERT</span><span class="hl opt">(</span><span class="hl kwd">validate</span><span class="hl opt">());</span> <span class="hl opt">}</span> <span class="hl com">/**</span> <span class="hl com"> * \fn ControlInfoMap &ControlInfoMap::operator=(const ControlInfoMap &other)</span> <span class="hl com"> * \brief Copy assignment operator, replace the contents with a copy of \a other</span> <span class="hl com"> * \param[in] other The other ControlInfoMap</span> <span class="hl com"> * \return A reference to the ControlInfoMap</span> <span class="hl com"> */</span> <span class="hl kwb">bool</span> <span class="hl kwc">ControlInfoMap</span><span class="hl opt">::</span><span class="hl kwd">validate</span><span class="hl opt">()</span> <span class="hl opt">{</span> <span class="hl kwa">for</span> <span class="hl opt">(</span><span class="hl kwb">const</span> <span class="hl kwc">auto</span> <span class="hl opt">&</span>ctrl <span class="hl opt">: *</span><span class="hl kwa">this</span><span class="hl opt">) {</span> <span class="hl kwb">const</span> ControlId <span class="hl opt">*</span>id <span class="hl opt">=</span> ctrl<span class="hl opt">.</span>first<span class="hl opt">;</span> <span class="hl kwc">auto</span> it <span class="hl opt">=</span> idmap_<span class="hl opt">-></span><span class="hl kwd">find</span><span class="hl opt">(</span>id<span class="hl opt">-></span><span class="hl kwd">id</span><span class="hl opt">());</span> <span class="hl com">/*</span> <span class="hl com"> * Make sure all control ids are part of the idmap and verify</span> <span class="hl com"> * the control info matches the expected type.</span> <span class="hl com"> */</span> <span class="hl kwa">if</span> <span class="hl opt">(</span>it <span class="hl opt">==</span> idmap_<span class="hl opt">-></span><span class="hl kwd">end</span><span class="hl opt">() ||</span> it<span class="hl opt">-></span>second <span class="hl opt">!=</span> id<span class="hl opt">) {</span> <span class="hl kwd">LOG</span><span class="hl opt">(</span>Controls<span class="hl opt">,</span> Error<span class="hl opt">)</span> <span class="hl opt"><<</span> <span class="hl str">"Control "</span> <span class="hl opt"><<</span> <span class="hl kwc">utils</span><span class="hl opt">::</span><span class="hl kwd">hex</span><span class="hl opt">(</span>id<span class="hl opt">-></span><span class="hl kwd">id</span><span class="hl opt">())</span> <span class="hl opt"><<</span> <span class="hl str">" not in the idmap"</span><span class="hl opt">;</span> <span class="hl kwa">return false</span><span class="hl opt">;</span> <span class="hl opt">}</span> <span class="hl com">/*</span> <span class="hl com"> * For string controls, min and max define the valid</span> <span class="hl com"> * range for the string size, not for the individual</span> <span class="hl com"> * values.</span> <span class="hl com"> */</span> ControlType rangeType <span class="hl opt">=</span> id<span class="hl opt">-></span><span class="hl kwd">type</span><span class="hl opt">() ==</span> ControlTypeString <span class="hl opt">?</span> ControlTypeInteger32 <span class="hl opt">:</span> id<span class="hl opt">-></span><span class="hl kwd">type</span><span class="hl opt">();</span> <span class="hl kwb">const</span> ControlInfo <span class="hl opt">&</span>info <span class="hl opt">=</span> ctrl<span class="hl opt">.</span>second<span class="hl opt">;</span> <span class="hl kwa">if</span> <span class="hl opt">(</span>info<span class="hl opt">.</span><span class="hl kwd">min</span><span class="hl opt">().</span><span class="hl kwd">type</span><span class="hl opt">() !=</span> rangeType<span class="hl opt">) {</span> <span class="hl kwd">LOG</span><span class="hl opt">(</span>Controls<span class="hl opt">,</span> Error<span class="hl opt">)</span> <span class="hl opt"><<</span> <span class="hl str">"Control "</span> <span class="hl opt"><<</span> <span class="hl kwc">utils</span><span class="hl opt">::</span><span class="hl kwd">hex</span><span class="hl opt">(</span>id<span class="hl opt">-></span><span class="hl kwd">id</span><span class="hl opt">())</span> <span class="hl opt"><<</span> <span class="hl str">" type and info type mismatch"</span><span class="hl opt">;</span> <span class="hl kwa">return false</span><span class="hl opt">;</span> <span class="hl opt">}</span> <span class="hl opt">}</span> <span class="hl kwa">return true</span><span class="hl opt">;</span> <span class="hl opt">}</span> <span class="hl com">/**</span> <span class="hl com"> * \brief Access specified element by numerical ID</span> <span class="hl com"> * \param[in] id The numerical ID</span> <span class="hl com"> * \return A reference to the element whose ID is equal to \a id</span> <span class="hl com"> */</span> <span class="hl kwc">ControlInfoMap</span><span class="hl opt">::</span>mapped_type <span class="hl opt">&</span><span class="hl kwc">ControlInfoMap</span><span class="hl opt">::</span><span class="hl kwd">at</span><span class="hl opt">(</span><span class="hl kwb">unsigned int</span> id<span class="hl opt">)</span> <span class="hl opt">{</span> <span class="hl kwa">return</span> <span class="hl kwd">at</span><span class="hl opt">(</span>idmap_<span class="hl opt">-></span><span class="hl kwd">at</span><span class="hl opt">(</span>id<span class="hl opt">));</span> <span class="hl opt">}</span> <span class="hl com">/**</span> <span class="hl com"> * \brief Access specified element by numerical ID</span> <span class="hl com"> * \param[in] id The numerical ID</span> <span class="hl com"> * \return A const reference to the element whose ID is equal to \a id</span> <span class="hl com"> */</span> <span class="hl kwb">const</span> <span class="hl kwc">ControlInfoMap</span><span class="hl opt">::</span>mapped_type <span class="hl opt">&</span><span class="hl kwc">ControlInfoMap</span><span class="hl opt">::</span><span class="hl kwd">at</span><span class="hl opt">(</span><span class="hl kwb">unsigned int</span> id<span class="hl opt">)</span> <span class="hl kwb">const</span> <span class="hl opt">{</span> <span class="hl kwa">return</span> <span class="hl kwd">at</span><span class="hl opt">(</span>idmap_<span class="hl opt">-></span><span class="hl kwd">at</span><span class="hl opt">(</span>id<span class="hl opt">));</span> <span class="hl opt">}</span> <span class="hl com">/**</span> <span class="hl com"> * \brief Count the number of elements matching a numerical ID</span> <span class="hl com"> * \param[in] id The numerical ID</span> <span class="hl com"> * \return The number of elements matching the numerical \a id</span> <span class="hl com"> */</span> <span class="hl kwc">ControlInfoMap</span><span class="hl opt">::</span>size_type <span class="hl kwc">ControlInfoMap</span><span class="hl opt">::</span><span class="hl kwd">count</span><span class="hl opt">(</span><span class="hl kwb">unsigned int</span> id<span class="hl opt">)</span> <span class="hl kwb">const</span> <span class="hl opt">{</span> <span class="hl com">/*</span> <span class="hl com"> * The ControlInfoMap and its idmap have a 1:1 mapping between their</span> <span class="hl com"> * entries, we can thus just count the matching entries in idmap to</span> <span class="hl com"> * avoid an additional lookup.</span> <span class="hl com"> */</span> <span class="hl kwa">return</span> idmap_<span class="hl opt">-></span><span class="hl kwd">count</span><span class="hl opt">(</span>id<span class="hl opt">);</span> <span class="hl opt">}</span> <span class="hl com">/**</span> <span class="hl com"> * \brief Find the element matching a numerical ID</span> <span class="hl com"> * \param[in] id The numerical ID</span> <span class="hl com"> * \return An iterator pointing to the element matching the numerical \a id, or</span> <span class="hl com"> * end() if no such element exists</span> <span class="hl com"> */</span> <span class="hl kwc">ControlInfoMap</span><span class="hl opt">::</span>iterator <span class="hl kwc">ControlInfoMap</span><span class="hl opt">::</span><span class="hl kwd">find</span><span class="hl opt">(</span><span class="hl kwb">unsigned int</span> id<span class="hl opt">)</span> <span class="hl opt">{</span> <span class="hl kwc">auto</span> iter <span class="hl opt">=</span> idmap_<span class="hl opt">-></span><span class="hl kwd">find</span><span class="hl opt">(</span>id<span class="hl opt">);</span> <span class="hl kwa">if</span> <span class="hl opt">(</span>iter <span class="hl opt">==</span> idmap_<span class="hl opt">-></span><span class="hl kwd">end</span><span class="hl opt">())</span> <span class="hl kwa">return</span> <span class="hl kwd">end</span><span class="hl opt">();</span> <span class="hl kwa">return</span> <span class="hl kwd">find</span><span class="hl opt">(</span>iter<span class="hl opt">-></span>second<span class="hl opt">);</span> <span class="hl opt">}</span> <span class="hl com">/**</span> <span class="hl com"> * \brief Find the element matching a numerical ID</span> <span class="hl com"> * \param[in] id The numerical ID</span> <span class="hl com"> * \return A const iterator pointing to the element matching the numerical</span> <span class="hl com"> * \a id, or end() if no such element exists</span> <span class="hl com"> */</span> <span class="hl kwc">ControlInfoMap</span><span class="hl opt">::</span>const_iterator <span class="hl kwc">ControlInfoMap</span><span class="hl opt">::</span><span class="hl kwd">find</span><span class="hl opt">(</span><span class="hl kwb">unsigned int</span> id<span class="hl opt">)</span> <span class="hl kwb">const</span> <span class="hl opt">{</span> <span class="hl kwc">auto</span> iter <span class="hl opt">=</span> idmap_<span class="hl opt">-></span><span class="hl kwd">find</span><span class="hl opt">(</span>id<span class="hl opt">);</span> <span class="hl kwa">if</span> <span class="hl opt">(</span>iter <span class="hl opt">==</span> idmap_<span class="hl opt">-></span><span class="hl kwd">end</span><span class="hl opt">())</span> <span class="hl kwa">return</span> <span class="hl kwd">end</span><span class="hl opt">();</span> <span class="hl kwa">return</span> <span class="hl kwd">find</span><span class="hl opt">(</span>iter<span class="hl opt">-></span>second<span class="hl opt">);</span> <span class="hl opt">}</span> <span class="hl com">/**</span> <span class="hl com"> * \fn const ControlIdMap &ControlInfoMap::idmap() const</span> <span class="hl com"> * \brief Retrieve the ControlId map</span> <span class="hl com"> *</span> <span class="hl com"> * Constructing ControlList instances for V4L2 controls requires a ControlIdMap</span> <span class="hl com"> * for the V4L2 device that the control list targets. This helper function</span> <span class="hl com"> * returns a suitable idmap for that purpose.</span> <span class="hl com"> *</span> <span class="hl com"> * \return The ControlId map</span> <span class="hl com"> */</span> <span class="hl com">/**</span> <span class="hl com"> * \class ControlList</span> <span class="hl com"> * \brief Associate a list of ControlId with their values for an object</span> <span class="hl com"> *</span> <span class="hl com"> * The ControlList class stores values of controls exposed by an object. The</span> <span class="hl com"> * lists returned by the Request::controls() and Request::metadata() functions</span> <span class="hl com"> * refer to the camera that the request belongs to.</span> <span class="hl com"> *</span> <span class="hl com"> * Control lists are constructed with a map of all the controls supported by</span> <span class="hl com"> * their object, and an optional ControlValidator to further validate the</span> <span class="hl com"> * controls.</span> <span class="hl com"> */</span> <span class="hl com">/**</span> <span class="hl com"> * \brief Construct a ControlList not associated with any object</span> <span class="hl com"> *</span> <span class="hl com"> * This constructor is meant to support ControlList serialization and shall not</span> <span class="hl com"> * be used directly by application.</span> <span class="hl com"> */</span> <span class="hl kwc">ControlList</span><span class="hl opt">::</span><span class="hl kwd">ControlList</span><span class="hl opt">()</span> <span class="hl opt">:</span> <span class="hl kwd">validator_</span><span class="hl opt">(</span><span class="hl kwc">nullptr</span><span class="hl opt">),</span> <span class="hl kwd">idmap_</span><span class="hl opt">(</span><span class="hl kwc">nullptr</span><span class="hl opt">),</span> <span class="hl kwd">infoMap_</span><span class="hl opt">(</span><span class="hl kwc">nullptr</span><span class="hl opt">)</span> <span class="hl opt">{</span> <span class="hl opt">}</span> <span class="hl com">/**</span> <span class="hl com"> * \brief Construct a ControlList with an optional control validator</span> <span class="hl com"> * \param[in] idmap The ControlId map for the control list target object</span> <span class="hl com"> * \param[in] validator The validator (may be null)</span> <span class="hl com"> *</span> <span class="hl com"> * For ControlList containing libcamera controls, a global map of all libcamera</span> <span class="hl com"> * controls is provided by controls::controls and can be used as the \a idmap</span> <span class="hl com"> * argument.</span> <span class="hl com"> */</span> <span class="hl kwc">ControlList</span><span class="hl opt">::</span><span class="hl kwd">ControlList</span><span class="hl opt">(</span><span class="hl kwb">const</span> ControlIdMap <span class="hl opt">&</span>idmap<span class="hl opt">,</span> <span class="hl kwb">const</span> ControlValidator <span class="hl opt">*</span>validator<span class="hl opt">)</span> <span class="hl opt">:</span> <span class="hl kwd">validator_</span><span class="hl opt">(</span>validator<span class="hl opt">),</span> <span class="hl kwd">idmap_</span><span class="hl opt">(&</span>idmap<span class="hl opt">),</span> <span class="hl kwd">infoMap_</span><span class="hl opt">(</span><span class="hl kwc">nullptr</span><span class="hl opt">)</span> <span class="hl opt">{</span> <span class="hl opt">}</span> <span class="hl com">/**</span> <span class="hl com"> * \brief Construct a ControlList with the idmap of a control info map</span> <span class="hl com"> * \param[in] infoMap The ControlInfoMap for the control list target object</span> <span class="hl com"> * \param[in] validator The validator (may be null)</span> <span class="hl com"> */</span> <span class="hl kwc">ControlList</span><span class="hl opt">::</span><span class="hl kwd">ControlList</span><span class="hl opt">(</span><span class="hl kwb">const</span> ControlInfoMap <span class="hl opt">&</span>infoMap<span class="hl opt">,</span> <span class="hl kwb">const</span> ControlValidator <span class="hl opt">*</span>validator<span class="hl opt">)</span> <span class="hl opt">:</span> <span class="hl kwd">validator_</span><span class="hl opt">(</span>validator<span class="hl opt">),</span> <span class="hl kwd">idmap_</span><span class="hl opt">(&</span>infoMap<span class="hl opt">.</span><span class="hl kwd">idmap</span><span class="hl opt">()),</span> <span class="hl kwd">infoMap_</span><span class="hl opt">(&</span>infoMap<span class="hl opt">)</span> <span class="hl opt">{</span> <span class="hl opt">}</span> <span class="hl com">/**</span> <span class="hl com"> * \typedef ControlList::iterator</span> <span class="hl com"> * \brief Iterator for the controls contained within the list</span> <span class="hl com"> */</span> <span class="hl com">/**</span> <span class="hl com"> * \typedef ControlList::const_iterator</span> <span class="hl com"> * \brief Const iterator for the controls contained within the list</span> <span class="hl com"> */</span> <span class="hl com">/**</span> <span class="hl com"> * \fn iterator ControlList::begin()</span> <span class="hl com"> * \brief Retrieve an iterator to the first Control in the list</span> <span class="hl com"> * \return An iterator to the first Control in the list</span> <span class="hl com"> */</span> <span class="hl com">/**</span> <span class="hl com"> * \fn const_iterator ControlList::begin() const</span> <span class="hl com"> * \brief Retrieve a const_iterator to the first Control in the list</span> <span class="hl com"> * \return A const_iterator to the first Control in the list</span> <span class="hl com"> */</span> <span class="hl com">/**</span> <span class="hl com"> * \fn iterator ControlList::end()</span> <span class="hl com"> * \brief Retrieve an iterator pointing to the past-the-end control in the list</span> <span class="hl com"> * \return An iterator to the element following the last control in the list</span> <span class="hl com"> */</span> <span class="hl com">/**</span> <span class="hl com"> * \fn const_iterator ControlList::end() const</span> <span class="hl com"> * \brief Retrieve a const iterator pointing to the past-the-end control in the</span> <span class="hl com"> * list</span> <span class="hl com"> * \return A const iterator to the element following the last control in the</span> <span class="hl com"> * list</span> <span class="hl com"> */</span> <span class="hl com">/**</span> <span class="hl com"> * \fn ControlList::empty()</span> <span class="hl com"> * \brief Identify if the list is empty</span> <span class="hl com"> * \return True if the list does not contain any control, false otherwise</span> <span class="hl com"> */</span> <span class="hl com">/**</span> <span class="hl com"> * \fn ControlList::size()</span> <span class="hl com"> * \brief Retrieve the number of controls in the list</span> <span class="hl com"> * \return The number of Control entries stored in the list</span> <span class="hl com"> */</span> <span class="hl com">/**</span> <span class="hl com"> * \fn ControlList::clear()</span> <span class="hl com"> * \brief Removes all controls from the list</span> <span class="hl com"> */</span> <span class="hl com">/**</span> <span class="hl com"> * \brief Merge the \a source into the ControlList</span> <span class="hl com"> * \param[in] source The ControlList to merge into this object</span> <span class="hl com"> *</span> <span class="hl com"> * Merging two control lists copies elements from the \a source and inserts</span> <span class="hl com"> * them in *this. If the \a source contains elements whose key is already</span> <span class="hl com"> * present in *this, then those elements are not overwritten.</span> <span class="hl com"> *</span> <span class="hl com"> * Only control lists created from the same ControlIdMap or ControlInfoMap may</span> <span class="hl com"> * be merged. Attempting to do otherwise results in undefined behaviour.</span> <span class="hl com"> *</span> <span class="hl com"> * \todo Reimplement or implement an overloaded version which internally uses</span> <span class="hl com"> * std::unordered_map::merge() and accepts a non-const argument.</span> <span class="hl com"> */</span> <span class="hl kwb">void</span> <span class="hl kwc">ControlList</span><span class="hl opt">::</span><span class="hl kwd">merge</span><span class="hl opt">(</span><span class="hl kwb">const</span> ControlList <span class="hl opt">&</span>source<span class="hl opt">)</span> <span class="hl opt">{</span> <span class="hl com">/**</span> <span class="hl com"> * \todo ASSERT that the current and source ControlList are derived</span> <span class="hl com"> * from a compatible ControlIdMap, to prevent undefined behaviour due to</span> <span class="hl com"> * id collisions.</span> <span class="hl com"> *</span> <span class="hl com"> * This can not currently be a direct pointer comparison due to the</span> <span class="hl com"> * duplication of the ControlIdMaps in the isolated IPA use cases.</span> <span class="hl com"> * Furthermore, manually checking each entry of the id map is identical</span> <span class="hl com"> * is expensive.</span> <span class="hl com"> * See https://bugs.libcamera.org/show_bug.cgi?id=31 for further details</span> <span class="hl com"> */</span> <span class="hl kwa">for</span> <span class="hl opt">(</span><span class="hl kwb">const</span> <span class="hl kwc">auto</span> <span class="hl opt">&</span>ctrl <span class="hl opt">:</span> source<span class="hl opt">) {</span> <span class="hl kwa">if</span> <span class="hl opt">(</span><span class="hl kwd">contains</span><span class="hl opt">(</span>ctrl<span class="hl opt">.</span>first<span class="hl opt">)) {</span> <span class="hl kwb">const</span> ControlId <span class="hl opt">*</span>id <span class="hl opt">=</span> idmap_<span class="hl opt">-></span><span class="hl kwd">at</span><span class="hl opt">(</span>ctrl<span class="hl opt">.</span>first<span class="hl opt">);</span> <span class="hl kwd">LOG</span><span class="hl opt">(</span>Controls<span class="hl opt">,</span> Warning<span class="hl opt">)</span> <span class="hl opt"><<</span> <span class="hl str">"Control "</span> <span class="hl opt"><<</span> id<span class="hl opt">-></span><span class="hl kwd">name</span><span class="hl opt">() <<</span> <span class="hl str">" not overwritten"</span><span class="hl opt">;</span> <span class="hl kwa">continue</span><span class="hl opt">;</span> <span class="hl opt">}</span> <span class="hl kwd">set</span><span class="hl opt">(</span>ctrl<span class="hl opt">.</span>first<span class="hl opt">,</span> ctrl<span class="hl opt">.</span>second<span class="hl opt">);</span> <span class="hl opt">}</span> <span class="hl opt">}</span> <span class="hl com">/**</span> <span class="hl com"> * \brief Check if the list contains a control with the specified \a id</span> <span class="hl com"> * \param[in] id The control numerical ID</span> <span class="hl com"> *</span> <span class="hl com"> * \return True if the list contains a matching control, false otherwise</span> <span class="hl com"> */</span> <span class="hl kwb">bool</span> <span class="hl kwc">ControlList</span><span class="hl opt">::</span><span class="hl kwd">contains</span><span class="hl opt">(</span><span class="hl kwb">unsigned int</span> id<span class="hl opt">)</span> <span class="hl kwb">const</span> <span class="hl opt">{</span> <span class="hl kwa">return</span> controls_<span class="hl opt">.</span><span class="hl kwd">find</span><span class="hl opt">(</span>id<span class="hl opt">) !=</span> controls_<span class="hl opt">.</span><span class="hl kwd">end</span><span class="hl opt">();</span> <span class="hl opt">}</span> <span class="hl com">/**</span> <span class="hl com"> * \fn ControlList::get(const Control<T> &ctrl) const</span> <span class="hl com"> * \brief Get the value of control \a ctrl</span> <span class="hl com"> * \param[in] ctrl The control</span> <span class="hl com"> *</span> <span class="hl com"> * Beside getting the value of a control, this function can also be used to</span> <span class="hl com"> * check if a control is present in the ControlList by converting the returned</span> <span class="hl com"> * std::optional<T> to bool (or calling its has_value() function).</span> <span class="hl com"> *</span> <span class="hl com"> * \return A std::optional<T> containing the control value, or std::nullopt if</span> <span class="hl com"> * the control \a ctrl is not present in the list</span> <span class="hl com"> */</span> <span class="hl com">/**</span> <span class="hl com"> * \fn ControlList::set(const Control<T> &ctrl, const V &value)</span> <span class="hl com"> * \brief Set the control \a ctrl value to \a value</span> <span class="hl com"> * \param[in] ctrl The control</span> <span class="hl com"> * \param[in] value The control value</span> <span class="hl com"> *</span> <span class="hl com"> * This function sets the value of a control in the control list. If the control</span> <span class="hl com"> * is already present in the list, its value is updated, otherwise it is added</span> <span class="hl com"> * to the list.</span> <span class="hl com"> *</span> <span class="hl com"> * The behaviour is undefined if the control \a ctrl is not supported by the</span> <span class="hl com"> * object that the list refers to.</span> <span class="hl com"> */</span> <span class="hl com">/**</span> <span class="hl com"> * \fn ControlList::set(const Control<T> &ctrl, const std::initializer_list<V> &value)</span> <span class="hl com"> * \copydoc ControlList::set(const Control<T> &ctrl, const V &value)</span> <span class="hl com"> */</span> <span class="hl com">/**</span> <span class="hl com"> * \brief Get the value of control \a id</span> <span class="hl com"> * \param[in] id The control numerical ID</span> <span class="hl com"> *</span> <span class="hl com"> * The behaviour is undefined if the control \a id is not present in the list.</span> <span class="hl com"> * Use ControlList::contains() to test for the presence of a control in the</span> <span class="hl com"> * list before retrieving its value.</span> <span class="hl com"> *</span> <span class="hl com"> * \return The control value</span> <span class="hl com"> */</span> <span class="hl kwb">const</span> ControlValue <span class="hl opt">&</span><span class="hl kwc">ControlList</span><span class="hl opt">::</span><span class="hl kwd">get</span><span class="hl opt">(</span><span class="hl kwb">unsigned int</span> id<span class="hl opt">)</span> <span class="hl kwb">const</span> <span class="hl opt">{</span> <span class="hl kwb">static const</span> ControlValue zero<span class="hl opt">;</span> <span class="hl kwb">const</span> ControlValue <span class="hl opt">*</span>val <span class="hl opt">=</span> <span class="hl kwd">find</span><span class="hl opt">(</span>id<span class="hl opt">);</span> <span class="hl kwa">if</span> <span class="hl opt">(!</span>val<span class="hl opt">)</span> <span class="hl kwa">return</span> zero<span class="hl opt">;</span> <span class="hl kwa">return</span> <span class="hl opt">*</span>val<span class="hl opt">;</span> <span class="hl opt">}</span> <span class="hl com">/**</span> <span class="hl com"> * \brief Set the value of control \a id to \a value</span> <span class="hl com"> * \param[in] id The control ID</span> <span class="hl com"> * \param[in] value The control value</span> <span class="hl com"> *</span> <span class="hl com"> * This function sets the value of a control in the control list. If the control</span> <span class="hl com"> * is already present in the list, its value is updated, otherwise it is added</span> <span class="hl com"> * to the list.</span> <span class="hl com"> *</span> <span class="hl com"> * The behaviour is undefined if the control \a id is not supported by the</span> <span class="hl com"> * object that the list refers to.</span> <span class="hl com"> */</span> <span class="hl kwb">void</span> <span class="hl kwc">ControlList</span><span class="hl opt">::</span><span class="hl kwd">set</span><span class="hl opt">(</span><span class="hl kwb">unsigned int</span> id<span class="hl opt">,</span> <span class="hl kwb">const</span> ControlValue <span class="hl opt">&</span>value<span class="hl opt">)</span> <span class="hl opt">{</span> ControlValue <span class="hl opt">*</span>val <span class="hl opt">=</span> <span class="hl kwd">find</span><span class="hl opt">(</span>id<span class="hl opt">);</span> <span class="hl kwa">if</span> <span class="hl opt">(!</span>val<span class="hl opt">)</span> <span class="hl kwa">return</span><span class="hl opt">;</span> <span class="hl opt">*</span>val <span class="hl opt">=</span> value<span class="hl opt">;</span> <span class="hl opt">}</span> <span class="hl com">/**</span> <span class="hl com"> * \fn ControlList::infoMap()</span> <span class="hl com"> * \brief Retrieve the ControlInfoMap used to construct the ControlList</span> <span class="hl com"> *</span> <span class="hl com"> * \return The ControlInfoMap used to construct the ControlList. ControlList</span> <span class="hl com"> * instances constructed with ControlList() or</span> <span class="hl com"> * ControlList(const ControlIdMap &idmap, ControlValidator *validator) have no</span> <span class="hl com"> * associated ControlInfoMap, nullptr is returned in that case.</span> <span class="hl com"> */</span> <span class="hl com">/**</span> <span class="hl com"> * \fn ControlList::idMap()</span> <span class="hl com"> * \brief Retrieve the ControlId map used to construct the ControlList</span> <span class="hl com"> * \return The ControlId map used to construct the ControlList. ControlList</span> <span class="hl com"> * instances constructed with the default contructor have no associated idmap,</span> <span class="hl com"> * nullptr is returned in that case.</span> <span class="hl com"> */</span> <span class="hl kwb">const</span> ControlValue <span class="hl opt">*</span><span class="hl kwc">ControlList</span><span class="hl opt">::</span><span class="hl kwd">find</span><span class="hl opt">(</span><span class="hl kwb">unsigned int</span> id<span class="hl opt">)</span> <span class="hl kwb">const</span> <span class="hl opt">{</span> <span class="hl kwb">const</span> <span class="hl kwc">auto</span> iter <span class="hl opt">=</span> controls_<span class="hl opt">.</span><span class="hl kwd">find</span><span class="hl opt">(</span>id<span class="hl opt">);</span> <span class="hl kwa">if</span> <span class="hl opt">(</span>iter <span class="hl opt">==</span> controls_<span class="hl opt">.</span><span class="hl kwd">end</span><span class="hl opt">()) {</span> <span class="hl kwd">LOG</span><span class="hl opt">(</span>Controls<span class="hl opt">,</span> Error<span class="hl opt">)</span> <span class="hl opt"><<</span> <span class="hl str">"Control "</span> <span class="hl opt"><<</span> <span class="hl kwc">utils</span><span class="hl opt">::</span><span class="hl kwd">hex</span><span class="hl opt">(</span>id<span class="hl opt">) <<</span> <span class="hl str">" not found"</span><span class="hl opt">;</span> <span class="hl kwa">return</span> <span class="hl kwc">nullptr</span><span class="hl opt">;</span> <span class="hl opt">}</span> <span class="hl kwa">return</span> <span class="hl opt">&</span>iter<span class="hl opt">-></span>second<span class="hl opt">;</span> <span class="hl opt">}</span> ControlValue <span class="hl opt">*</span><span class="hl kwc">ControlList</span><span class="hl opt">::</span><span class="hl kwd">find</span><span class="hl opt">(</span><span class="hl kwb">unsigned int</span> id<span class="hl opt">)</span> <span class="hl opt">{</span> <span class="hl kwa">if</span> <span class="hl opt">(</span>validator_ <span class="hl opt">&& !</span>validator_<span class="hl opt">-></span><span class="hl kwd">validate</span><span class="hl opt">(</span>id<span class="hl opt">)) {</span> <span class="hl kwd">LOG</span><span class="hl opt">(</span>Controls<span class="hl opt">,</span> Error<span class="hl opt">)</span> <span class="hl opt"><<</span> <span class="hl str">"Control "</span> <span class="hl opt"><<</span> <span class="hl kwc">utils</span><span class="hl opt">::</span><span class="hl kwd">hex</span><span class="hl opt">(</span>id<span class="hl opt">)</span> <span class="hl opt"><<</span> <span class="hl str">" is not valid for "</span> <span class="hl opt"><<</span> validator_<span class="hl opt">-></span><span class="hl kwd">name</span><span class="hl opt">();</span> <span class="hl kwa">return</span> <span class="hl kwc">nullptr</span><span class="hl opt">;</span> <span class="hl opt">}</span> <span class="hl kwa">return</span> <span class="hl opt">&</span>controls_<span class="hl opt">[</span>id<span class="hl opt">];</span> <span class="hl opt">}</span> <span class="hl opt">}</span> <span class="hl com">/* namespace libcamera */</span> </code></pre></td></tr></table> </div> <!-- class=content --> <div class='footer'>generated by <a href='https://git.zx2c4.com/cgit/about/'>cgit v1.2.1</a> (<a href='https://git-scm.com/'>git 2.18.0</a>) at 2025-03-01 08:17:09 +0000</div> </div> <!-- id=cgit --> </body> </html>