KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jscience > physics > quantities > Quantity


1 /*
2  * JScience - Java(TM) Tools and Libraries for the Advancement of Sciences.
3  * Copyright (C) 2005 - JScience (http://jscience.org/)
4  * All rights reserved.
5  *
6  * Permission to use, copy, modify, and distribute this software is
7  * freely granted, provided that this notice is preserved.
8  */

9 package org.jscience.physics.quantities;
10
11 import javolution.util.FastMap;
12 import javolution.lang.MathLib;
13 import javolution.lang.Text;
14 import javolution.xml.XmlElement;
15 import javolution.xml.XmlFormat;
16 import javolution.realtime.RealtimeObject;
17
18 import org.jscience.mathematics.numbers.Number;
19 import org.jscience.physics.units.ConversionException;
20 import org.jscience.physics.units.Converter;
21 import org.jscience.physics.units.Unit;
22
23 /**
24  * <p> This class represents a measurable amount. The nature of the amount
25  * is deduced from the quantity unit. The quality of the measurement
26  * is given by the measurement error.</p>
27  *
28  * <p> Errors (including numeric errors) are calculated using numeric intervals.
29  * It is possible to resolve systems of linear equations involving physical
30  * quantities (e.g. using {@link org.jscience.mathematics.matrices.Matrix}),
31  * even if the system is close to singularity; in which case the error
32  * associated with some (or all) components of the solution may be large.
33  * </p>
34  *
35  * <p> The decimal representations of quantities instances are indicative of
36  * their precision as only digits guaranteed to be exact are written out.
37  * For example, the string <code>"2.000 km/s"</code> represents a
38  * {@link Velocity} of <code>(2.0 ± 0.001) km/s</code>.</p>
39  *
40  * <p> Finally, operations between quantities may or may not be authorized
41  * based upon the current {@link org.jscience.physics.models.PhysicalModel
42  * PhysicalModel} (e.g. adding a {@link Length length} to a {@link Duration
43  * duration} is not allowed by the
44  * {@link org.jscience.physics.models.StandardModel StandardModel},
45  * but is authorized with the {@link
46  * org.jscience.physics.models.RelativisticModel RelativisticModel}).</p>
47  *
48  * @author <a HREF="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
49  * @version 2.0, June 6, 2005
50  */

51 public class Quantity extends Number JavaDoc<Quantity> {
52
53     /**
54      * Holds the default XML representation for physical quantities.
55      * This representation consists of an <code>amount</code> and
56      * an <code>unit</code> attribute.
57      * The unit attribute determinates the quantity type. For example:<pre>
58      * &lt;Quantity amount="12.3" unit="µA"/&gt;</pre>
59      * represents an {@link ElectricCurrent} instance.
60      */

61     private static final XmlFormat<Quantity> XML = new XmlFormat<Quantity>(
62             Quantity.class) {
63         public void format(Quantity q, XmlElement xml) {
64             xml.setAttribute("amount", q.getAmount());
65 // xml.newAttribute("error")
66
// .append(q.getAbsoluteError(), 4, false, false);
67
if (q._unit != Unit.ONE) {
68                 xml.setAttribute("unit", q._unit.toText());
69             }
70         }
71
72         public Quantity parse(XmlElement xml) {
73             double amount = xml.getAttribute("amount", 0.0);
74 // double error = xml.getAttribute("error", 0.0);
75
CharSequence JavaDoc unitName = xml.getAttribute("unit");
76             Unit unit = unitName != null ? Unit.valueOf(unitName) : Unit.ONE;
77             return Quantity.valueOf(amount, unit);
78         }
79     };
80
81     /**
82      * Holds the relative error due to the inexact representation of
83      * <code>double</code> values (64 bits IEEE 754 format).
84      */

85     static final double DOUBLE_RELATIVE_ERROR = MathLib.pow(2, -53);
86
87     /**
88      * Holds the factor decrementing <code>double</code> values by
89      * exactly one LSB.
90      */

91     static final double DECREMENT = (1.0 - DOUBLE_RELATIVE_ERROR);
92
93     /**
94      * Holds this quantity unit.
95      */

96     private Unit _unit;
97
98     /**
99      * Holds the minimum amount stated in this quantity base units
100      */

101     private double _minimum;
102
103     /**
104      * Holds the maximum amount stated in this quantity base units.
105      */

106     private double _maximum;
107
108     //////////////////
109
// Construction //
110
//////////////////
111

112     /**
113      * Default constructor.
114      */

115     protected Quantity() {
116     }
117
118     /**
119      * Returns the quantity corresponding to the specified character sequence.
120      * The unit of the specified quantity determinates the class of the quantity
121      * being returned. For example:<pre>Quantity.valueOf("1.2 GeV")</pre>
122      * returns an {@link Energy} instance.
123      *
124      * @param csq the character sequence.
125      * @return <code>QuantityFormat.current().parse(csq)</code>
126      * @throws IllegalArgumentException if the specified character sequence
127      * cannot be parsed.
128      * @see QuantityFormat
129      */

130     public static <Q extends Quantity> Q valueOf(CharSequence JavaDoc csq) {
131         return (Q) QuantityFormat.current().parse(csq);
132     }
133
134     /**
135      * Returns the quantity for the specified amount.
136      * The specified unit determinates the class of the quantity being returned.
137      * For example:<pre>Quantity.valueOf(30, NonSI.FOOT)</pre>
138      * returns a {@link Length} instance.
139      *
140      * @param amount the estimated amount (± 1/2 LSB).
141      * @param unit the amount's unit.
142      * @return the corresponding quantity.
143      */

144     public static <Q extends Quantity> Q valueOf(double amount, Unit<Q> unit) {
145         Converter cvtr = unit.toBaseUnits();
146         double value = cvtr.convert(amount);
147         return (Q) newInstance(unit).setRangeApprox(value, value);
148     }
149
150     /**
151      * Returns the quantity of specified amount and measurement error.
152      * The specified unit determinates the class of the quantity being returned.
153      * For example:<pre>Quantity.valueOf(20, 0.1, SI.KILO(SI.HERTZ))</pre>
154      * returns a {@link Frequency} instance.
155      *
156      * @param amount the estimated amount (± error).
157      * @param error the measurement error (absolute).
158      * @param unit the amount's unit.
159      * @return the corresponding quantity.
160      */

161     public static <Q extends Quantity> Q valueOf(double amount, double error,
162             Unit<Q> unit) {
163         Converter cvtr = unit.toBaseUnits();
164         double min = cvtr.convert(amount - error);
165         double max = cvtr.convert(amount + error);
166         return (Q) newInstance(unit).setRangeApprox(min, max);
167     }
168
169     /**
170      * Returns the quantity whose amount is in the specified range.
171      *
172      * @param minimum the lower bound for the quantity amount.
173      * @param maximum the upper bound of the quantity amount.
174      * @param unit the bounds unit.
175      * @return the corresponding quantity.
176      */

177     public static <Q extends Quantity> Q rangeOf(double minimum,
178             double maximum, Unit<Q> unit) {
179         Converter cvtr = unit.toBaseUnits();
180         double min = cvtr.convert(minimum);
181         double max = cvtr.convert(maximum);
182         return (Q) newInstance(unit).setRangeApprox(min, max);
183     }
184
185     /**
186      * Returns this quantity estimated amount stated in this quantity
187      * {@link #getUnit unit}.
188      *
189      * @return this quantity estimated amount.
190      */

191     public double getAmount() {
192         double baseUnitValue = (_minimum + _maximum) * 0.5;
193         Converter cvtr = _unit.toBaseUnits().inverse();
194         return cvtr.convert(baseUnitValue);
195     }
196
197     /**
198      * Returns the unit identifying this quantity type; it is also
199      * the unit in which this quantity is displayed by default.
200      *
201      * @return the unit for this quantity.
202      */

203     public Unit getUnit() {
204         return _unit;
205     }
206
207     /**
208      * Returns the minimum value for this quantity stated in base units.
209      *
210      * @return the minimum value.
211      */

212     public final double getMinimum() {
213         return _minimum;
214     }
215
216     /**
217      * Returns the maximum value for this quantity stated in base units.
218      *
219      * @return the maximum amount value.
220      */

221     public final double getMaximum() {
222         return _maximum;
223     }
224
225     /**
226      * Returns the value by which the {@link #doubleValue estimated value}
227      * may differ from the true value (all stated in base units).
228      *
229      * @return the absolute error stated in base units.
230      */

231     public final double getAbsoluteError() {
232         return MathLib.abs(_maximum - _minimum) / 2.0;
233     }
234
235     /**
236      * Returns the percentage by which the estimated amount may differ
237      * from the true amount.
238      *
239      * @return the relative error.
240      */

241     public final double getRelativeError() {
242         return (_maximum - _minimum) / (_minimum + _maximum);
243     }
244
245     ////////////////
246
// Operations //
247
////////////////
248

249     /**
250      * Returns the quantity equivalent to this quantity but stated
251      * using the specified unit. This method may return a quantity
252      * of different type than this quantity (the unit determinates
253      * the quantity sub-class).
254      *
255      * @param unit the unit of the quantity being returned.
256      * @return a quantity equivalent to this unit but stated using
257      * a different unit.
258      * @throws ConversionException if the current model does not allows for
259      * conversion to the specified unit.
260      */

261     public final <Q extends Quantity> Q to(Unit<Q> unit) {
262         Quantity q = newInstance(unit);
263         if (!needConversionTo(unit)) // Most likely.
264
return (Q) q.setRangeExact(_minimum, _maximum);
265         Converter cvtr = _unit.getBaseUnits().getConverterTo(
266                 unit.getBaseUnits());
267         double min = cvtr.convert(_minimum);
268         double max = cvtr.convert(_maximum);
269         return (Q) q.setRangeApprox(min, max);
270     }
271
272     /**
273      * Returns the opposite of this quantity.
274      *
275      * @return <code>-this</code>.
276      */

277     public final Quantity opposite() {
278         return Quantity.newInstance(_unit).setRangeExact(-_maximum, -_minimum);
279     }
280
281     /**
282      * Returns the sum of this quantity with the one specified.
283      *
284      * @param that the quantity to be added.
285      * @return <code>this + that</code>.
286      * @throws ConversionException if the current model does not allows for
287      * these quantities to be added.
288      */

289     public final Quantity plus(Quantity that) throws ConversionException {
290         if (needConversionTo(that._unit))
291             return this.plus(that.to(_unit));
292         return Quantity.newInstance(_unit).setRangeApprox(
293                 this._minimum + that._minimum, this._maximum + that._maximum);
294     }
295
296     /**
297      * Returns the difference of this quantity with the one specified.
298      *
299      * @param that the quantity to be subtracted.
300      * @return <code>this - that</code>.
301      * @throws ConversionException if the current model does not allows for
302      * these quantities to be subtracted.
303      */

304     public final Quantity minus(Quantity that) throws ConversionException {
305         if (needConversionTo(that._unit))
306             return this.minus(that.to(_unit));
307         return Quantity.newInstance(_unit).setRangeApprox(
308                 this._minimum - that._maximum, this._maximum - that._minimum);
309     }
310
311     /**
312      * Returns this quantity multiplied by the specified factor.
313      *
314      * @param factor the multiplier.
315      * @return <code>this * factor</code>.
316      */

317     public final Quantity times(double factor) {
318         return (factor > 0) ? Quantity.newInstance(_unit).setRangeApprox(
319                 this._minimum * factor, this._maximum * factor) : Quantity
320                 .newInstance(_unit).setRangeApprox(this._maximum * factor,
321                         this._minimum * factor);
322     }
323
324     /**
325      * Returns the product of this quantity with the one specified.
326      *
327      * @param that the quantity multiplier.
328      * @return <code>this * that</code>.
329      */

330     public final Quantity times(Quantity that) {
331         double min, max;
332         if (_minimum >= 0) {
333             if (that._minimum >= 0) {
334                 min = _minimum * that._minimum;
335                 max = _maximum * that._maximum;
336             } else if (that._maximum < 0){
337                 min = _maximum * that._minimum;
338                 max = _minimum * that._maximum;
339             } else {
340                 min = _maximum * that._minimum;
341                 max = _maximum * that._maximum;
342             }
343         } else if (_maximum < 0) {
344             if (that._minimum >= 0) {
345                 min = _minimum * that._maximum;
346                 max = _maximum * that._minimum;
347             } else if (that._maximum < 0){
348                 min = _maximum * that._maximum;
349                 max = _minimum * that._minimum;
350             } else {
351                 min = _minimum * that._maximum;
352                 max = _minimum * that._minimum;
353             }
354         } else {
355             if (that._minimum >= 0) {
356                 min = _minimum * that._maximum;
357                 max = _maximum * that._maximum;
358             } else if (that._maximum < 0){
359                 min = _maximum * that._minimum;
360                 max = _minimum * that._minimum;
361             } else { // Both around zero.
362
min = MathLib.min(_minimum * that._maximum, _maximum * that._minimum);
363                 max = MathLib.max(_minimum * that._minimum, _maximum * that._maximum);
364             }
365         }
366         return newInstance(this._unit.times(that._unit)).setRangeApprox(min,
367                 max);
368     }
369
370     /**
371      * Returns the reciprocal of this quantity.
372      * If this quantity is possbily zero, then the resulting quantity
373      * is unbounded.
374      *
375      * @return <code>1 / this</code>.
376      */

377     public final Quantity reciprocal() {
378         Quantity q = newInstance(_unit.inverse());
379         if ((_minimum <= 0) && (_maximum >= 0)) { // Encompass zero.
380
return q.setRangeExact(Double.NEGATIVE_INFINITY,
381                     Double.POSITIVE_INFINITY);
382         }
383         return q.setRangeApprox(1.0 / _maximum, 1.0 / _minimum);
384     }
385
386     /**
387      * Returns this quantity divided by the specified divisor.
388      *
389      * @param divisor the divisor.
390      * @return <code>this / divisor</code>.
391      */

392     public final Quantity divide(double divisor) {
393         return (divisor > 0) ? Quantity.newInstance(_unit).setRangeApprox(
394                 this._minimum / divisor, this._maximum / divisor) : Quantity
395                 .newInstance(_unit).setRangeApprox(this._maximum / divisor,
396                         this._minimum / divisor);
397     }
398
399     /**
400      * Returns the square root of this quantity.
401      *
402      * @return <code>sqrt(this)</code>
403      */

404     public final Quantity sqrt() {
405         return newInstance(_unit.root(2)).setRangeApprox(
406                 MathLib.sqrt(_minimum), MathLib.sqrt(_maximum));
407     }
408
409     /**
410      * Returns the given root of this quantity.
411      *
412      * @param n the root's order (n &gt;= 0).
413      * @return the result of taking the given root of this quantity.
414      * @throws ArithmeticException if <code>n == 0</code>.
415      */

416     public final Quantity root(int n) {
417         if (n > 0) {
418             Quantity q = newInstance(_unit.root(n));
419             return q.setRangeApprox(MathLib.pow(_minimum, 1.0 / n), MathLib
420                     .pow(_maximum, 1.0 / n));
421         } else if (n < 0) {
422             return root(-n).reciprocal();
423         } else {
424             throw new ArithmeticException JavaDoc("Root's order of zero");
425         }
426     }
427
428     /**
429      * Returns the magnitude (positive) of this quantity.
430      *
431      * @return <code>|this|</code>.
432      */

433     public final Quantity norm() {
434         return (_minimum >= -_maximum) ? this : this.opposite();
435     }
436
437     /**
438      * Compares this quantity amount with that quantity amount ignoring
439      * the sign.
440      *
441      * @return <code>|this| > |that|</code>
442      */

443     public final boolean isLargerThan(Quantity that) {
444         return MathLib.abs(this._minimum + this._maximum) > MathLib
445                 .abs(that._minimum + that._maximum);
446     }
447
448     //////////////////////
449
// General Contract //
450
//////////////////////
451

452     /**
453      * Indicates if this quantity is strictly equals to the object specified
454      * (same amount and same system unit).
455      *
456      * <p> Note: Unlike {@link #approxEquals}, this method does not take into
457      * account possible errors (e.g. numeric errors).</p>
458      *
459      * @param obj the object to compare with.
460      * @return <code>true</code> if this quantity and the specified object
461      * represent the exact same quantity; <code>false</code> otherwise.
462      */

463     public boolean equals(Object JavaDoc obj) {
464         if (!(obj instanceof Quantity))
465             return false;
466         Quantity that = (Quantity) obj;
467         if (this._unit != that._unit)
468             return false;
469         return (this._minimum == that._minimum)
470                 && (this._maximum == that._maximum);
471     }
472
473     /**
474      * Returns a well distributed hash code value for this quantity.
475      *
476      * @return this quantity hash code value.
477      * @see #equals
478      */

479     public int hashCode() {
480         int h = Float.floatToIntBits((float) _maximum);
481         h += ~(h << 9);
482         h ^= (h >>> 14);
483         h += (h << 4);
484         return h ^ (h >>> 10);
485     }
486
487     /**
488      * Indicates if this quantity is approximately equals to the specified
489      * quantity (regardless of the quantity unit). This method takes into
490      * account possible errors (e.g. numeric errors) to make this determination.
491      *
492      * @param that the quantity to compare with.
493      * @return <code>this &ape; that</code>.
494      */

495     public boolean approxEquals(Quantity that) {
496         if (!this._unit.isCompatible(that._unit))
497             return false;
498         Quantity diff = this.minus(that);
499         return (diff._minimum <= 0) && (diff._maximum >= 0);
500     }
501
502     /**
503      * Compares this quantity with the specified quantity for order.
504      * Returns a negative integer, zero, or a positive integer as this quantity
505      * is less than, equal to, or greater than the specified quantity.
506      * This method does not require both units to be stated using the same
507      * units.
508      *
509      * @param that the quantity to be compared.
510      * @return a negative integer, zero, or a positive integer as this quantity
511      * is less than, equal to, or greater than that quantity.
512      * @throws ConversionException if the current model does not allows for
513      * these quantities to be compared.
514      * @see org.jscience.physics.units.Unit#isCompatible
515      */

516     public int compareTo(Quantity that) {
517         if (!this._unit.isCompatible(that._unit))
518             throw new ConversionException("Cannot compare quantity in "
519                     + this._unit + " with quantity in " + that._unit);
520         double diff = this.minus(that).doubleValue();
521         if (diff < 0)
522             return -1;
523         if (diff > 0)
524             return 1;
525         if (this.equals(that))
526             return 0;
527         // Special cases (e.g. NaN), do not return 0 for consistency with equal.
528
long rawBits = Double.doubleToLongBits(diff);
529         return (rawBits < 0) ? -1 : 1;
530     }
531
532     /**
533      * Returns the textual representation of this quantity.
534      * By default the quantity amount stated in the quantity unit.
535      *
536      * @return the textual representation of this quantity.
537      * @see QuantityFormat
538      */

539     public Text toText() {
540         return QuantityFormat.current().format(this);
541     }
542
543     /**
544      * Returns the estimated value stated in base units represented as a
545      * <code>long</code>.
546      *
547      * @return the numeric value after conversion to type <code>long</code>.
548      */

549     public final long longValue() {
550         return MathLib.round(doubleValue());
551     }
552
553     /**
554      * Returns the estimated value stated in base units represented as a
555      * <code>double</code>.
556      *
557      * @return the numeric value after conversion to type <code>double</code>.
558      */

559     public final double doubleValue() {
560         return 0.5 * (_minimum + _maximum);
561     }
562
563     /**
564      * Returns a new quantity instance stated in the specified unit.
565      *
566      * @param unit the unit identifying the quantity type.
567      * @return the corresponding quantity.
568      */

569     private static Quantity newInstance(Unit unit) {
570         Factory< ? extends Quantity> factory = Factory.UNIT_TO_FACTORY
571                 .get(unit);
572         if (factory != null) {
573             Quantity q = factory.object();
574             q._unit = unit;
575             return q;
576         }
577         return newInstanceCacheMiss(unit);
578     }
579
580     private static Quantity newInstanceCacheMiss(Unit unit) {
581         Factory< ? extends Quantity> factory = Factory.getInstance(unit);
582         Quantity q = factory.object();
583         q._unit = unit;
584         return q;
585     }
586
587     /**
588      * Indicates if the base units of this quantity are identical to the
589      * base units to this quantity.
590      *
591      * @param unit the unit the unit to be compared with.
592      * @return <code>true</code> if this quantity and quantity stated in
593      * the specified unit need conversions; <code>false</code>
594      * otherwise.
595      */

596     private boolean needConversionTo(Unit unit) {
597         return (_unit != unit) && (_unit.getBaseUnits() != unit.getBaseUnits());
598     }
599
600     /**
601      * This inner-class represents the factory producing quantity instances.
602      * {@link Quantity} instances.
603      */

604     public static abstract class Factory<Q extends Quantity> extends
605             RealtimeObject.Factory<Q> {
606
607         /**
608          * Holds the factory producing general purpose quantities.
609          */

610         private static final Factory GENERAL = new Factory() {
611             protected Object JavaDoc create() {
612                 return new Quantity();
613             }
614         };
615
616         /**
617          * Holds the quantity factories instances (indexed by system unit).
618          */

619         private static final FastMap<Unit, Factory< ? extends Quantity>> COLLECTION = new FastMap<Unit, Factory< ? extends Quantity>>(
620                 256);
621
622         /**
623          * Holds the unit to quantity factory mapping (cache).
624          */

625         private static final FastMap<Unit, Factory< ? extends Quantity>> UNIT_TO_FACTORY = new FastMap<Unit, Factory< ? extends Quantity>>(
626                 1024);
627
628         /**
629          * Default constructor.
630          */

631         protected Factory() {
632         }
633
634         /**
635          * Creates a new factory and associates it to the specified unit.
636          *
637          * @param unit the unit to which this factory is used for.
638          * @see #useFor(Unit)
639          */

640         protected Factory(Unit<Q> unit) {
641             useFor(unit);
642         }
643
644         /**
645          * Maps the specified unit to this factory. Quantities having the
646          * specified unit will be automatically produced by this factory.
647          *
648          * @param unit the unit mapped to this factory.
649          * @return <code>this</code>
650          * @throws IllegalArgumentException if the unit is already
651          * associated to another factory.
652          */

653         public Factory<Q> useFor(Unit unit) {
654             synchronized (COLLECTION) {
655                 if (COLLECTION.containsKey(unit))
656                     throw new IllegalArgumentException JavaDoc("unit: " + unit
657                             + " is already mapped");
658                 COLLECTION.put(unit, this);
659                 // Clears the factory cache (set values to null to keep
660
// access unsynchronized).
661
for (FastMap.Entry<Unit, Factory< ? extends Quantity>> e = UNIT_TO_FACTORY
662                         .headEntry(), end = UNIT_TO_FACTORY.tailEntry(); (e = e
663                         .getNextEntry()) != end;) {
664                     e.setValue(null);
665                 }
666             }
667             return this;
668         }
669
670         /**
671          * Returns the factory for the specified unit, this method searches
672          * for the factory directly mapped to the specified unit, then for the
673          * factory mapped to the base units of the specified unit.
674          * If none is found, a general purpose factory is returned.
675          *
676          * @param unit the unit for which the current factory is searched for.
677          * @return the factory producing quantities for the specified unit.
678          */

679         private static Factory< ? extends Quantity> getInstance(Unit unit) {
680             Factory< ? extends Quantity> factory = UNIT_TO_FACTORY.get(unit);
681             if (factory != null)
682                 return factory;
683             // Not in the cache.
684
while (true) {
685                 factory = COLLECTION.get(unit);
686                 if (factory != null) break;
687                 if (unit.getParentUnit() == unit) {
688                     factory = GENERAL;
689                     break;
690                 }
691                 unit = unit.getParentUnit();
692             }
693             synchronized (UNIT_TO_FACTORY) {
694                 UNIT_TO_FACTORY.put(unit, factory);
695             }
696             return factory;
697         }
698     }
699
700     private Quantity setRangeExact(double min, double max) {
701         _minimum = min;
702         _maximum = max;
703         return this;
704     }
705
706     private Quantity setRangeApprox(double min, double max) {
707         if (min >= 0) { // max >= 0 as well.
708
_minimum = min * DECREMENT;
709             _maximum = max + max * DOUBLE_RELATIVE_ERROR;
710         } else if (max <= 0) { // min <= 0 as well.
711
_minimum = min + min * DOUBLE_RELATIVE_ERROR;
712             _maximum = max * DECREMENT;
713         } else { // min < 0 < max
714
_minimum = min + min * DOUBLE_RELATIVE_ERROR;
715             _maximum = max + max * DOUBLE_RELATIVE_ERROR;
716         }
717         return this;
718     }
719
720     // Forces initialization of predefined quantities.
721
static {
722         org.jscience.JScience.initialize();
723     }
724     
725     private static final long serialVersionUID = 1L;
726 }
Popular Tags